Should a property in Swift be implicitly unwrapped in my UIViewControllers?

88 Views Asked by At

Let's say we have this viewController

public class DetailsViewController : UITableViewController
{
    public var text : String;
    public override func viewDidLoad ( )
    {
        // do something with text
    }
}

and we have this other controller that pushes the previous one via a segue

public class MainViewController : UITableViewController
{
    ...

     public override func prepareForSegue ( segue : UIStoryboardSegue, sender : AnyObject? )
     {
         if ( segue.identifier == "detailsSegue" )
         {
             let selectPatientController = segue.destinationViewController as! DetailsViewController;
             selectPatientController.text = "I'm Iron Man";
         }
     }
}

Since MainViewController does not instantiate DetailsViewController, I cannot guarantee that "text" will be set. So I can either declare it as "String?" or "String!".

  • "String?": I would have to write ".text?" in viewDidLoad. If MainViewController does not set the property, I would probably have a view with a missing text.

  • "String!": simpler code, but the app crashes if MainViewController does not set the property.

What is the best option for a possible error: display an incomplete view or crash and get the error log? The last one is unpleasant for users, but it helps bug track, specially in development time.

I think a good solution is to use "String?" with assert(), and then the app would crash only in development time. Other suggestions?

2

There are 2 best solutions below

0
On

Here is how I would do it.

If you can set default text

public class DetailsViewController : UITableViewController
{
    public var text : String = "Default text or empty string" {
        didSet {
            //property was just changed so you can update your UI with new text
            //for example (you need to define this function yourself)
            self.updateWhenTextChanged()
        }
    }
    public override func viewDidLoad ( )
    {
        // do something with text
    }
}

If you cannot set default text

Leave it as String?. It might be a pain to unwrap it (although in Swift 2.0 guard statements help a lot), but this way you will ensure that your code is safe.

It might be tempting to put String!, but what if for whatever reason you stop using segues in the future and will load your view controller programatically, through xibs or through some new method which Apple introduces? Just imagine how painful it will be to find all those implicitly unwrapped variables and fix them!

0
On

I would agree with your initial thought about ?. I think it is right approach. Also suggestion by Andriy about default parameter is also a nice one if applicable.

Your code should express your understanding of all situations possible in it. If you are not sure yourself that text will be defined by the moment when it will be accessed it should be ?. There is no reason to hide it. This will give enough guidance to other developers about possible complications, so they will be able to work with your code appropriately. Even if user is not able to proceed further with incomplete data, developer still will be able to handle such scenario and allow user to leave application gracefully. I would avoid ! by all cost as potential point of runtime error that will bring negative UX as well as hard to debug afterward.