4

I've read a few articles about it and understand the basic principle and do agree that it could be useful in some cases. However, most of the time I would want my program to crash if I was getting nil somewhere that I shouldn't be -- that's how'd I know there was a problem!

Furthermore I've read that using optionals can lead to shorter code.. How is that possible?? From what I've seen the whole idea behind them is they can either have a value or nil so you have to do additional checking whereas previously that wasn't necessary!

And what's up with needing to use "as" all the time? It just makes everything more verbose and lengthy. For example, compare the following code in Objective-C and Swift

Objective-C:

UIViewController *vc = [self.storyboard instantiateViewControllerWithIdentifier:@"Home"];
AppDelegate *appDelegate = [[UIApplication sharedApplication] delegate];
appDelegate.window.rootViewController = vc;
[UIView transitionWithView:appDelegate.window
                          duration:0.2
                          options:UIViewAnimationOptionTransitionCrossDissolve
                          animations:^{ appDelegate.window.rootViewController = vc; }
                          completion:nil];

Swift:

//have to check if self.storyboard != nil
let viewController:UIViewController = self.storyboard?.instantiateViewControllerWithIdentifier("Home") as UIViewController; //Isn't the view controller returned by instantiateViewControllerWithIdentifier() already of type UIViewController?
let appDelegate:AppDelegate = UIApplication.sharedApplication().delegate as AppDelegate; //Isn't the delegate returned by sharedApplication() already of type AppDelegate?
//have to check if appDelegate.window != nil
appDelegate.window!.rootViewController = viewController as UIViewController; //Why cast viewController as UIViewController if the type has already been explicitly set above?

UIView.transitionWithView(
    appDelegate.window!,
    duration: 0.2,
    options: UIViewAnimationOptions.TransitionCrossDissolve,
    animations:{appDelegate.window!.rootViewController = viewController as UIViewController},
    completion: nil
);

Am I doing something wrong? Or is this really the way that it was intended to be?

Mick MacCallum
  • 129,200
  • 40
  • 280
  • 281
  • The "as" at the end replaces the type at the beginning in Objective-C, so that's pretty much a wash as far as verbosity. You also don't need both ":ClassName" and "as ClassName" -- you don't need the ":ClassName" before the "=". You also shouldn't have the line ending semicolons in Swift – rdelmar Mar 15 '15 at 16:57
  • 1
    Check the docs for return types. No, the return type for instantiateViewControllerWithIdentifier is not UIViewController, it's id. That's why you need the "as" – rdelmar Mar 15 '15 at 17:00
  • Probably because Swift is dumb, though. It will not automatically coerce. You have to explicitly cast one into the other. Ups - where`s your comment? – qwerty_so Mar 15 '15 at 17:06
  • Ah, that explains that. Thanks. I still don't really understand why to use optionals though. Of course you want to catch when something is `nil` but at the cost of having to always be checking for `nil`? Seems like a lot more code to me – null pointer exception Mar 15 '15 at 17:07
  • For what it's worth, the Objective-C code would be just as verbose, if not more so if you were actually including checks to make sure that your variables were of the types that you assume they are, and `respondsToSelector:` checks on method calls and property access. – Mick MacCallum Mar 15 '15 at 17:17
  • I'm also not really convinced of the optional concept. But that's an opinion based discussion which is not welcome here on SO. – qwerty_so Mar 15 '15 at 19:24

1 Answers1

3

Optionals

If you know for sure that a variable should never be nil, you can force unwrap an optional using ! or declare as implicitly unwrapped using String!. This will cause a crash when it is nil, exactly like you want.

But, with some variables it is reasonable for them to be nil. For example, a User model whose age variable isn't set because the user didn't supply it.

Explicitly marking them as optional and unwrapping them using if let forces you to think about nullability. In the end, this creates more robust code.

I don't think it leads to shorted code. Where in Objective-C you would use if var != nil you use if let var = var in Swift. Sending a message to nil in Obj-C is a noop, you can get the same behavior in Swift using var?.method(). It's kinda the same in the end.

Casting (as)

A big reason you need casts right now in Swift is because some Objective-C methods return id, which was no problem in Obj-C but causes trouble in Swift. I expect this to diminish as Swift becomes more popular and frameworks are adapted.

Updated code

I quickly looked over your code and it looks you don't need half those casts. This is from the top of my head:

if let viewController = self.storyboard?.instantiateViewControllerWithIdentifier("Home") as? UIViewController {
    if let window = UIApplication.sharedApplication().delegate?.window {
        window.rootViewController = viewController

        UIView.transitionWithView(window, duration: 0.2, options: .TransitionCrossDissolve, animations: {
            window.rootViewController = viewController
        }, completion: nil);
    }
}
Rengers
  • 14,911
  • 1
  • 36
  • 54
  • Ah thanks perfect explanation of why "as" is needed. As for optionals, it looks as if in general it's better to just be a bit more verbose and use `if let var = var` rather than just force unwrapping then? It just kills me having to add all of those checks when `self.storyboard` for example should never be `nil` anyways. But if it was, wouldn't you want your program to crash so you knew exactly what the issue was? This seems to almost make it harder to debug.. – null pointer exception Mar 15 '15 at 17:30
  • So I just popped your code into Xcode and `window.rootViewController = viewController` is giving me the error "'UIWindow?' does not have a member named 'rootViewController'" – null pointer exception Mar 15 '15 at 17:32
  • It depends on the situation. For storyboards I force unwrap because I *know* that it is not nil. And even if it was nil, my app wouldn't be able to continue, so I'm ok with crashing at that point. – Rengers Mar 15 '15 at 17:32
  • Good to know, that's more in line with how I would expect it to look. As for the above error I just force unwrapped window `if let window = UIApplication.sharedApplication().delegate?.window!` – null pointer exception Mar 15 '15 at 17:38
  • It looks like it is explained here: http://stackoverflow.com/questions/28901893/why-is-main-window-of-type-double-optional – Rengers Mar 15 '15 at 17:41