Re: Instantiate NSString from NSURL in Swift
Re: Instantiate NSString from NSURL in Swift
- Subject: Re: Instantiate NSString from NSURL in Swift
- From: Fritz Anderson <email@hidden>
- Date: Mon, 23 Feb 2015 13:52:53 -0600
On 23 Feb 2015, at 8:18 AM, Juanjo Conti <email@hidden> wrote:
>
> I'm translating some code from Objective-C to Swift and in the middle of
> that, i found this problem.
>
> theUrl is an instance of NSURL
>
> theUrl.host?.lowercaseString
>
> compiles ok.
>
> But
>
> NSString(string: theUrl.host?.lowercaseString)
> don't. It says "Value of optional type 'String?' no unwrapped; did you mean
> to use '!' or '?'?
>
> If I click to add the fix, then it complains again and suggest to delete
> the '!' :)
This is written in haste, and few people are experts…
theURL.host may yield nil (host is declared String!, implicitly unwrapped, but optional).
theURL.host?.lowercaseString will short-circuit and be evaluated as nil if .host is nil.
anyString.lowercaseString may also yield nil; the var is declared String!.
anyString.lowercaseString! attempts to unwrap a String that the compiler has implicitly unwrapped already.
Therefore, because of the short-circuit “?”, the expression theUrl.host?.lowercaseString is of type String?, which may be .None (nil), or .Some(String) (and therefore have to be unwrapped).
You are passing that optional String as the argument for String(string: {that optional expression}). The argument may be nil; or it may need unwrapping. The initializer _requires_ a non-nil argument. It’s a righteous error.
The expression
NSString(string: foo!)
is different; by adding the bang you’ve taken responsibility for the parameter’s not being nil.
Because .lowercaseString returns an implicitly-unwrapped String (String!),
theURL?.host?.lowercaseString!
tries to unwrap something that is already, syntactically, an unwrapped String.
Quincey — my instinct is that the conditional-unwrap chain necessarily forces left-to-right evaluation, tighter than the . operator. The ! would mean, “if you got this far without short-circuiting, and b returns an optional, then unwrap it.”
As of today’s Swift 1.2b2, the following in a playground:
let aURL = NSURL(string: "http://wt9t.com/")!
NSString(string: aURL.host?.lowercaseString)
complains as you suggest: .host? is potentially nil — that would force the whole expression to be nil, and thus forbidden as a parameter. lowercaseString still gets treated as implicitly unwrapped — so a bang at the end of the whole expression is an attempt to unwrap something the compiler was going to unwrap anyway.
By the way: The use of +[NSString stringWithString:] or -[NSString initWithString:] is a code smell. The result of lowercaseString is declared as immutable, and you aren’t trying to initialize an NSMutableString with it. Foundation (unless I’m missing something) is free to treat it just as it does with -[NSString copy], and simply return the same object with the retain count bumped. Once you get into mutability, the smell goes away, and someone will surely jump in now with an explanation for why it’s needed more often than I think.
— F
_______________________________________________
Cocoa-dev mailing list (email@hidden)
Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com
Help/Unsubscribe/Update your Subscription:
This email sent to email@hidden