> On Mar 10, 2015, at 21:17, Roland King <r...@rols.org> wrote: > > >> On 11 Mar 2015, at 00:24, Bill Cheeseman <wjcheese...@gmail.com> wrote: >> >> I'm using Xcode 6.2 and Swift 1.1. >> >> 1. The following statement reports the error "'NSURL?' does not have a >> member named 'path'" even though executableURL has a trailing exclamation >> point to unwrap it. The caret identifying the location of the error is >> placed under the exclamation point. >> >> for thisApp in NSWorkspace.sharedWorkspace().runningApplications { >> let thisPath = thisApp.executableURL!.path // ERROR >> } >> >> If I change executableURL to bundleURL, the error goes away. Yet >> executableURL and bundleURL are declared identically according to the >> NSRunningApplication reference document. As far as I know, bundleURL and >> executableURL both satisfy fileURL. >> >> The error also goes away if I assign thisApp to a local variable and >> expressly downcast it to NSRunningApplication, as shown below. Why would I >> need to do that with executableURL, when it isn't necessary with bundleURL? >> >> for thisApp in NSWorkspace.sharedWorkspace().runningApplications { >> let myAppAndIMeanIt = thisApp as NSRunningApplication >> let thisPath = myAppAndIMeanIt.executableURL!.path // NO ERROR >> } >> >> Is this a Swift bug? >> > > No, one of yours again - although I don't really understand what's going on > with the plethora of optionals it's pretty easy, using something I've > recommended dozens of times, to gain insight into what the compiler thinks > it's doing by, as usual, splitting the line up into two assignments and using > opt option+click to see what type it has guessed things are. > > In the first case if you split out thisApp.executableURL into its own line > you will find it's of type 'NSURL?!'. I actually don't know entirely what > that means, an implicitly unwrapped optional to an optional. I suppose it's > means it's possibly something which is possibly an NSURL with an implicit > guarantee that it's not nothing at all.
.executableURL has type NSURL? in all Cocoa classes that provide it (NSBundle & NSRunningApplication), so that’s one optionality level. Note that `thisApp` has type AnyObject because NSWorkspace.runningApplications() returns [AnyObject]. But thisApp.executableURL forces Swift to downcast `thisApp` to some type that provides .executableURL, and this downcast might succeed or not — there’s the other optionality level. > Anyway your '!' before '.path' just unwraps the implicitly unwrapped optional > bit. Yes I know it's implicitly unwrapped already but I believe the '!' just > unwraps it from implicitly unwrapped optional to optional NSURL to really > unwrapped, ie optional NSURL. So you need two '!!', one for the '!' and one > for the '?'. > > let thisPath = thisApp.executableURL!!.path > > I tried to move the ugliness around a bit, you can do > > for thisApp in NSWorkspace.sharedWorkspace().runningApplications as [ > NSRunningAppliction ] > { > let thisPath = thisApp.executableURL!.path > } > > except in 6.3 now you can't do that, you have to have 'as!', so it isn't much > nicer although possibly more consistent > > > Why does this happen with executableURL and not bundleURL, I don't really > know. Both those properties are defined on both NSBundle and > NSRunningApplication however the bundleURL is non-optional on both of them > and the executableURL is optional on NSRunningApplication but not on > NSBundle. Since runningApplications returns an [ AnyObject ] I assume there's > one level of optionality in err ... something and then another one in > executableURL because it might be optional, or not. Much like in Objective-C. If you write void someFunction(id obj) { NSLog(@"%@", [obj bundleURL]); } the compiler picks *some* method that matches that selector—which method is undefined. This can be problematic when multiple methods have the same selector but different types; in particular, when one method has a floating-point type in its signature and another method doesn’t. In Objective-C, -bundleURL isn’t a problem. In Swift, it can be a problem because NSBundle.bundleURL has type NSURL (not an optional) whereas NSRunningApplication.bundleURL has type NSURL? (an optional). In Bill’s case, the compiler is choosing NSBundle.bundleURL. Which method/property is chosen is probably undefined in Swift as well. > > Amusing crash of the day whilst trying to work this out > > import Cocoa > > for thisApp in NSWorkspace.sharedWorkspace().runningApplications > { > //let pp = thisApp as! NSRunningApplication > let tt = thisApp.bundleURL!.path > } > > works fine. However if you uncomment the commented line, which does nothing > but set an unused variable, the line below crashes with EXC_i386_INVOP. > That's 6.3, in 6.2 you have to remove the '!' in the commented line after the > 'as', however you still get the same crash. > > All this to work around nil, a concept I've always rather liked. _______________________________________________ Cocoa-dev mailing list (Cocoa-dev@lists.apple.com) 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: https://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com This email sent to arch...@mail-archive.com