Why does Swift insist on this being an optional? - swift

Caveat: I've been coding in Swift for about 2 days!
I am following along with some simple tutorials to build a status menu application. The following is a reduction of my AppDelegate.swift class:
import Cocoa
#NSApplicationMain
class AppDelegate: NSObject, NSApplicationDelegate {
#IBOutlet weak var window: NSWindow!
#IBOutlet weak var statusMenu: NSMenu!
let statusItem = NSStatusBar.systemStatusBar().statusItemWithLength(-2)
func applicationDidFinishLaunching(aNotification: NSNotification) {
let icon = NSImage(named: "StatusBarImage")
icon?.setTemplate(true)
}
}
My question is, why does Xcode insist that my icon constant be an optional (it was also OK with me forcing it to be unwrapped). The tutorial didn't show that the ? was needed, but Xcode shows me the following error if I leave it out:
Value of optional type 'NSImage' not unwrapped; did you mean to use '!' or '?'?
(I'm using Xcode 6.4, if that makes a difference.)

From Document:
Declaration:
init?(named name: String) -> NSImage
Which means by default it's initialiser is an optional.
Return Value
The NSImage object associated with the specified name or nil if no
such image was found.
Discussion
The NSImage class may cache a reference to the returned image object
for performance in some cases. However, the class holds onto cached
objects only while the object exists. If all strong references to the
image are subsequently removed, the object may be quietly removed from
the cache. Thus, if you plan to hold onto a returned image object, you
must maintain a strong reference to it like you would any Cocoa
object. You can clear an image object from the cache explicitly by
calling the object’s setName: method and specifying nil for the image
name.
That's why it is asking you did you mean to use '!' or '?'
So if you use ! that means you are unwrapping optional value and if you use ? compiler will consider it as optional.

Because image named StatusBarImage might as well not be in the assets and it would result in bad access exception.

Actually Xcode is not forcing anything : if you check the NSImage documentation you will see that the NSImage initializer is a failable initializer.
Like #FruitAddict said the whole point of those initializers is to fail gracefully (by returning an optional with a nil value) when the object could not be created. Check Apple Developer Blog

By adding ! or this ? You know explicitly that imageNamed can returned you a nil.
And Compiler just makes sure that you know about it.

Related

Swift performance on optional UI elements

Setting up a UILabel in Swift I can do the following
#IBOutlet var wLabel: UILabel!
or
#IBOutlet var wLabel: UILabel?
Setting the text I can either do
wLabel.text = "..."
or, for the latter do
wLabel?.text = "..." // with a question mark for the optional
Keeping them optional will help for the case when they are unexpectedly nil as it will just skip this call then and go ahead with the code. Having them declared with the ! would crash the app if the label was nil.
Now why would you not make everything optional? The only reason I could think of would be for better performance. Should I stay away from having them optional if my app has a lot of UI elements so them being optional would mean a disadvantage regarding performance? I wasn't able to find any information on this anyhere.
Using ? in your Outlet will make your code untracable
Crashes are very good in some scenarios, because if no crash is there then it becomes super difficult to trace even small error.
Consider the examples of #IBOutlet with !:
#IBOutlet var wLabel: UILabel!
wLabel.isEnabled = true
Just remove the connection of your Outlet label from your storyboard and run the app, your app will crash on wLabel.isEnabled = true. Since you got a crash so you can got to your storyboard see whether the connection is proper or not. In case there is no connect you add it and damn! you solved the problem easily.
Now consider the examples of #IBOutlet with ?:
#IBOutlet var wLabel: UILabel?
wLabel?.isEnabled = true
Do the same thing, just remove the connection of your Outlet label from your storyboard and run the app, your app won't crash at all. You won't be able to know the error, hence making your code a mess and untracable.
Apple guys were very aware of optional thing, they did force unwrapping of #IBOutlet for a reason. And of course there is no performance difference between ! and ?
If you're setting something up as an outlet it's set up as a force unwrapped optional (with exclamation mark !) because Swift requires your classes to have all of their properties initialized when the object is constructed (i.e. init method is called). Outlets are not created during object construction but rather assigned later when the xib or storyboard data is loaded into your component. Force unwrapped optionals are basically a way to say that you guarantee that the property will be initialized after object's init is called and before they're used.
There are no performance gains to using either of these. An Optional? type means that the property can either be nil or have a value. A force unwrapped optional ! means that the property is guaranteed to have a value when it is used. Upholding this is up to the developer and using such property if its value is nil will result in a crash.

swift and sharedapplication

first post!
i've been working with swift for a while now, but decided to move some of my code to using shared variables and objects. I'm having a fundamental issue with being able to reference appDelegate.SharedApplication().delegate. Even with a basic test application (to see if I could see any fundamental problems), I cannot get a reference to the shared variable -
// AppDelegate.swift
#UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
let info: String = "test"
}
trying to add - "let ref = UIApplication.sharedApplication().delegate as appDelegate" in another class complains of use of undeclared type app delegate.
removing that cast allows that, but once I try to create another variable reference to the info string, complains of no member named ref.
this seems such an obvious and confusing issue that I thought it time to ask for an answer :) all i want is to be able to use the appdelegate for controlling cllocationmanager and storing the return data in a variable for a view controller class to refer to.
xcode 6.1.1
cheers
Maybe you are confusing the compiler because you are not using the proper case (upper or lower) when referring to variables or classes.
A class starts with an UpperCase letter.
Any variable starts with a lowerCase letter.
While this is not a rule for variables, it is a well-heeded convention.
Thus:
let stringFromDelegate =
(UIApplication.sharedApplication() as AppDelegate).info

Type and declaration restrictions on Swift capture specifiers

I'm confused about the type requirements and declaration restrictions for Swift capture specifiers. The documentation says that weak references must be var and "of optional type", and that unowned references must be of non-optional type. But Apple's own API reference has examples of unowned(unsafe) references declared as optionals, while the Xcode interface builder creates weak outlets and actions that are implicitly unwrapped (which is not always clearly "of optional type" in the language reference).
What types are required for each of the Swift capture specifiers? Which must be var and which can be let?
FWIW, I think its
weak can be Type? or Type!, but not Type; and must be var
unowned(safe) (same as unowned) must be Type; and may be let
unowned(unsafe) can be Type? or Type!; and may be let
but I'm far from sure.
First the Cocoaor Cocoa touch APIs are imported in swift fromobjective-c`. They are mapped in swift with best possible ways.So that both can interoperable.
Those unowned(unsafe) properties are marked as assign in ObjC. These are unsafe and ARC doesn't retain the object, and it doesn't make sure the reference gets reset to nil if the object is deallocated. These are old apple API and not changed with ARC and remain asassignbut you should makedelegateweak`
Do not look for headers for best practices in swift they have made many tricks to make swift and objective-c interoperable and if you do what headers do than you loose all safety swift proveide.
You are right
weak should be optional as contain nil automatically if objects get deallocate and no other pointer retain it
unowned(safe) should not be optional and will not reset to nilif objects deal-located
unowned(unsafe) can or can not be optional as it not provide any safety by ARC for object deal-location and do not reset to nil.You should not use this in swift program.Use unowned if needed.It is just for interoperability.
weak is always var because it can be changed when objects deallocate and set to nil.
unowned(safe) and unowned(unsafe) can be both var or let as they are dependent on you and run-time will not change these variables.
Note:You can not declare a unowned(unsafe) as optional in swift program.Its for just interoperability and should not be used in swift.They have made this because of assign or unretain properties can be nil

Size classes - traitCollectionDidChange crashes with nil value

I have a swift project with a storyboard using Size Classes, a ViewController which conforms to the UITraitEnvironment protocol and have implemented the function traitCollectionDidChange.
When I first launch the app traitCollectionDidChange is called which seems reasonable - it allows developers to handle the first size class presented by the application, however the previousTraitCollection variable passed to it is nil. I can't check that this value is nil as its NOT optional, and accessing it in any way causes a crash. Changing the parameter to optional in the function declaration causes a build error, complaining that I have not implemented required methods in the protocol.
For now I have managed to work around this by creating a separate function which takes an optional variable of the same type that I can then check against, but I would like to know why this is happening.
If its any use to anyone at all, here is the function I am overriding
override func traitCollectionDidChange(previousTraitCollection: UITraitCollection) {
// Accessing previousTraitCollection causes a crash
}
Can anyone shed any light on this?
You have to declare that the type of the argument is optional, because accessing it forces the compiler to try and unpack the address which causes the crash. Replace it with:
override func traitCollectionDidChange(previousTraitCollection: UITraitCollection?) {
// Accessing previousTraitCollection causes a crash
}

Calling method using optional chaining on weak variable causes EXC_BAD_ACCESS

Update: This is fixed in Xcode 6 beta 6.
The following code causes an EXC_BAD_ACCESS on the delegate?.thing() line:
#class_protocol protocol Fooable {
func foo()
}
class Bar : Fooable {
func foo() {
}
}
weak var delegate: Fooable?
let bar = Bar()
delegate = bar
delegate?.foo()
But everything seems right to me. In order for a variable to be weak, it must have optional type. So the variable delegate is optional. A weak variable's type must also be a class type, so I made the protocol a class protocol. Since I use optional chaining, I expect it to either 1) be nil, and do nothing, or 2) not be nil, and call the method, which should succeed. However, it crashes.
Could it be that optional chaining is not atomic and doesn't retain the expression and the object somehow gets deallocated in between the check for nil and the subsequent call?
Interestingly, if you eliminate the variable bar and assign it directly as delegate = Bar(), the crash goes away. This is really perplexing because assigning an expression to a variable and then assigning the variable and assigning the expression directly should generally behave the same.
I suspect the reason weak var delegate: Fooable?is not working is because that line of code, which is using optional chaining, is checking for protocol conformance.
According to Apple Swift Programming manual:
“Even if you are not interoperating with Objective-C, you need to mark
your protocols with the #objc attribute if you want to be able to
check for protocol conformance.”
If you substitute #class_protocol with #objc it should not crash. Also as per the manual, using #objc only allows the protocol to be adopted by classes (no structs or enums conformance).
Like #PartiallyFinite, I had to play with the code a little too. Apple's iBook on Swift has a blurb about this that may help (with a protocol named ExampleProtocol and a class SimpleClass that conforms to that protocol):
"Even though the variable protocolValue has a runtime type of SimpleClass, the compiler treats it as the given type of ExampleProtocol. This means that you can’t accidentally access methods or properties that the class implements in addition to its protocol conformance.”
That said, you should be able to call foo() on your delegate (barring it doesn't go away before calling it), but just remember the delegate here is declared to be of type Fooable?, not Bar, under the hood. This may be a bug, but I got it to work by entering:
weak var delegate: Bar? = bar
delegate?.foo()