preface

For iOS development, writing a custom View, or using a TableView properly, is basically “line work.” But after seeing some students write custom controls, sometimes feel like writing is not good enough, although it can work normally, but in the scalability, ease of use, and stability are lacking. So I plan to write a series, called how to Write good XXX, to summarize what I think good writing should be, this is the first part of the series.

Of course, limited by vision and level, some of the things mentioned in the article are not necessarily the optimal solution, we are very welcome to put forward different opinions, after discussion grow together!

The target

  • Various ways of use
    • Used in pure code
    • Used in Xib/storyboard
  • Ease of use
    • Keep interface design simple
    • As little exposure as possible
    • Handling of abnormal situations

implementation

Initialization method

Here we can take a look at how UI components of systems in UIKit design their own initialization methods.

There are basically two classes of initialization methods in UIKit,

  • Designated Initializer inherited from the parent class

    • initWithFrame
    • InitWithCoder (Not all UI classes inherit UIView, like UIBarItem inherit NSObject, these don’t have an initWithFrame method)
  • Convenience Initializer, for example, in UITabBarItem

    - (instancetype)initWithTitle:(nullable NSString *)title image:(nullable UIImage *)image tag:(NSInteger)tag; - (instancetype)initWithTitle:(nullable NSString *)title image:(nullable UIImage *)image selectedImage:(nullable UIImage  *)selectedImage NS_AVAILABLE_IOS(7_0); - (instancetype)initWithTabBarSystemItem:(UITabBarSystemItem)systemItem tag:(NSInteger)tag;Copy the code

    Methods such as

First, we need to figure out what Designated Initializer and Convenience initializer are.

  • Designated Initializer is a mandatory attribute for an initializer class
  • The Convenience Initializer provides a convenient initialization method and provides default values for some attributes as required. The internal implementation of the method will eventually call the Designated Initializer.

Second, why do subclasses of UIView have two Designated Initializers? So these are the two ways we talked about using a View, Xib/storyboard and pure code.

Realize the Designated, initializer

In order to satisfy both the pure code approach and the Xib approach, we need to implement two Designated Initializers for CustomView

And in Swift, initWithCoder is already marked as required, so it must be implemented

In both ways, the main thing to do is add child views and provide default values

To provide Convenience, Initializer

UIImageView, for example, provides initWithImage, the Convenience Initializer.

The benefit of using Convenience Initializer is that it lets users of a class know exactly how to initialize the class correctly. It also provides default values for required properties, greatly preventing the caller from simply calling init and causing the instance to fail, and providing a simple initialization method for many properties.

Implementation of internal sub-view layout

Frame or autoLayout?

If we use frames, we need to make sure that the Subviews change automatically when the size of the Custom View changes, instead of keeping the original frame. (autoresizingMask,autoresizesSubviews)

With autoLayout, there is no such problem, and the only thing to consider is performance. WWDC also shows that although Apple has repeatedly optimized Autolayout, its performance is still far inferior to Frame’s in multi-view scenarios

In my opinion, I prefer AutoLayout if the page level is not complex and the performance difference is not significant. After all, it is difficult to calculate the frame and the code readability is much worse than AutoLayout

Build view

A few important methods need to be explained, and when should they be used

  • – (void)drawRect:(CGRect)rect
    • Use scenario: When you need to draw a page using Core Graphics or UIKit, you do not need to override this method if you are composing your own view using the existing UI control AddSubView
    • When called: When the view is displayed for the first time, or when an event causes the view to be updated, do not call it manually. To redraw, call setNeedsDisplay or setNeedsDisplayInRect:
    • Parameter description: The view needs to update the scope, if it is a continuous drawing, then rect may only be part of the view
  • – (void)layoutSubviews
    • Usage scenario: Rewrite layoutSubviews to provide a more accurate layout only when autoresizing and constraints don’t meet your needs
    • When called: Do not call the constraint manually. Call setNeedsLayout to update the constraint. If you need to update the constraint immediately, call layoutIfNeeded
  • – (void)updateConstraints;
    • Usage scenario: In order to optimize the change of constraints, the constraints need to be changed in advance, or a large number of redundant changes are generated.
    • Is called time: don’t directly call manually, in the view needs to change constraints, called setNeedsUpdateConstraints
    • Matters needing attention:
      • At the end of the implementation, call [Super updateConstraints]
      • Don’t call setNeedsUpdateConstraints in method, can produce cycle

Interface design

Interface design follows Effective Objective-C 2.0 recommendations, such as readonly properties that must be exposed, and private methods that are implemented internally. When you’re designing your interface, always think, does this method, this property really need to be known? What is the real purpose of this approach? Just Keep It Simple, Stupid.

Thread management

All UI operations should be done in the main thread, which requires us to ensure that UI changes are done in the main thread and not dependent on the user

A simple example

TCZoomingImageView is based on UIScrollView and UIImageView to do a scalable View, the implementation is very simple, just as a simple example, to draw a line.

GitHub address: TCZoomingImageView

The resources

UIView Document From Apple

View Programming Guide for iOS

IOS creates the posture of the object

Object Initialization

Discuss performance from Auto Layout Layout algorithm

WWDC: High Performance Auto Layout

WWDC:Mysteries of Auto Layout, Part 1

[WWDC:Mysteries of Auto Layout, Part 2