قالب وردپرس درنا توس
Home / IOS Development / Kill the ViewDidLoad configuration in Swift

Kill the ViewDidLoad configuration in Swift



Back in Objective-C, we prepared all our control features in viewDidLoad because it was our only option unless we wanted to subdivide each item to provide customized initiatives. Using some tricks in Swift, we can provide clear readable initialization outside viewDidLoad which makes the code easier to read and explain.

The Old Bad Way

Here's a traditional viewDidLoad that I would have written when you start in a new viewer in Swift after working in Objective-C the previous year:

  class    ViewController             la    topView    =    UIView () 

      ride    FUNC    viewDidLoad  ()    {1
9659018] topView.frame
= CGRect ( 0 0 100 200 ) TopView. backgroundColor = UIColor.redColor () view .addSubview (topView) } }

We initialize our topView as a property because we want access to other places for animation etc. Once the e-view is loaded, we configure the parts of the view we want to change before you place it as an education. This is fine to watch for a single view (albeit slightly offline), but you can see how this can quickly mess up as more and more views are configured and added under viewDidLoad . class class ] ViewController : UIViewController {
la baseline = UIView ()
la image = UIImageView ()
la goButton = UIButton ()

ride FUNC viewDidLoad () {
topView.frame = [19659007] CGRect (x: 0 y: 0 width: 100 ] height: 200 [19659006])
topView.backgroundColor = UIColor.redColor ()
view.addSubview (top view)

imageView.image = ] UIImage (19659000]] [profile] )
topView.addSubview (imageVis) [19659076] goButton.frame = CGRect (x: 0 ] y: 0 width: 30 [19659007] height: 30 )
goButton.setTitle (19659086) "GO" forState: .Normal)
view.addSubview (goButton)
]}
}

… and so on.

Convert to initialization shutdowns

With Swift we can minimize the amount of code ordered in viewDidLoad and move most of the configuration to the same room we use for initialization of property. The Swift documentation mentions these as a way to provide property configuration, but does not give them a specific name. I'm fond of the term " Initialization Closure ".

By moving these configuration steps up to the Initialization Point, we keep the related configuration code together and keep the display code in the right place. After adding 10 other parts of this view controller, you can still tell exactly where to go to change some configuration details without digging through and the entire viewing hierarchy setup. class ViewController : [19659007] UIViewController {
la 19659007] 0 y: 0 Width: 19659007] = UIView ()
Viewing .frame = Width: 100 height: 200 )
view.backgroundColor = UIColor.redColor ()
return view
} imageVis: imageVis: UIImageView = {
la imageView = UIImageView ()
imageView.image = UIImage (named: [19659079] "profile" )
return imageVis
} () [19659013] la goButton: UIButton = [19659007] {
la button = UIButton ()
b utton.frame = [19659007] CGRect (x: 0 y: 0 width: 30 height: 30 )
button.setTitle "GO" forState: .Normal)
return button
} 19659013] ride FUNC viewDidLoad () {
view.addSubview (top view)
topView.addSubview (imageVis)
view.addSubview (goButton)
}
}

Actually, now that we have decoupled the configuration from the display setup, we are more free to place the display layout in what might be a more appropriate placement, sometimes viewDidAppear viewDidLayoutSubviews etc. I know I loved keeping them all in viewDidLoad simply because it was easier to group in all configurations and layouts together.

In most cases, this is actually the behavior we want; set up our properties when the parent object is initialized, and do little work to set up the view when required. In rare cases where initialization takes a long time, you may see a difference in behavior, but it is likely that there will be a controlled viewer when it is located in viewDidLoad . These highly latent tasks are better off the main thread completely, initialized after the parent object is created and placed in an optional feature so you can unpack and say if any asynchronous process has completed or not.

Storyboard people are also people

I know there are at least a few people who prefer to set up their views in Storyboards themselves and feel excluded by awesome Swift tool club right now. Fortunately, there is a solution for them too and it can only make you a storyboard convert. In the same way that we can customize get and set properties, we can also provide our own implementation for didSet and willSet and then use them in connection with @IBOutlet .

I have to admit that I like to put my views and limitations in Storyboards because I find myself adapting the element spacing all the time and it is much clearer to move items in Storyboard preview than to look at the simulator and then guess hard-coded numbers . One thing I do not like likes to do in Storyboards, however, configures display details. The right pane of the Storyboard editor is a mess and if you can not find what you want to customize, you do not know if it's just hidden or it can not be adjusted in Interface Builder at all.

Not sure which of these is standard or how to share them between items

The solution is to place your views and limitations in the Interface Builder and then configure them in code. It's surprisingly easy to make the basics of Storyboards just to get a feel of how the scene will look and how it's all connected and it improves the search configuration of the display configuration code. If you create common styles across your app, you can even customize them in the didSet block instead of doing the same configuration every time.

  class    ViewController :   ] UIViewController    {
      @IBOutlet    weak    var    arrivalLabel:!    UILabel    {
          didSet    {
              arrivalLabel.text    =    "Arrives in 10 minutes"  .uppercaseString 
              arrivalLabel.font    =    UIFont (name:    "CirceBold"     size:    11 ) 
              arrivalLabel.textColor    =    UIColor.blueColor () 
              ArrivalLabel.textAlignment    =    .Center 
              ArrivalLabel.numberOfLines    = [19659023] 1 
        } 
    } 

      @IBOutlet    weak    Var    departureLabel :!    UILabel    {
          didSet    {
              stiler. setStandardLabelStyles 
        } 
    } 

Some Gotchas with Bad Error Messages:

  • Remember to call the initialization closure with () . I forget this all the time. Otherwise, you assign a shutdown, not the result of the closure, to another type like UIView and you get Can not convert the value of the & # 39; () -> _ & # 39; to specified type error.

  • Another remarkable issue you may encounter is Can not assign the value of the & # 39; NSObject -> () -> ViewController & # 39; to write & # 39; ImagePickerDelegate & # 39; or similar phrasing when you try to insert property to yourself inside an initialization shutdown. I suspect this is just a problem with even not really existing before all the properties are initialized and an error message that only makes sense if you know Swift internals. Fortunately, it's a simple solution: Only make the property lazy and even will exist when initialization closes.

Here is an example of setting up an ImagePicker as a property where we want to set up a delegate and limit how many images can be selected:

  class    ViewController :    UIViewController [19659007]             imagePickerController:    ImagePickerController    =    {
         ] la    Select    =    ImagePickerController ()    picker.delegate    =    even 
          picker.imageLimit    =    1 
          return [19659007] picker 
    } () 
} 

Questions or comments? Find us at twitter or send a problem on github




Source link