I plan to write a series of short “bite-sized” articles covering fundamentals of Go. I have done programming in many languages, and believe that programming language is just a tool, which sometimes we have to learn. So that’s the reason I decided to write from perspective of engineer who may be interested expanding horizons, or just have to learn new technology for a new job.
Loading Swift UIViewController from XIB in storyboard
Some developers prefer to keep ViewControllers design in separate XIB files instead of placing everything in Storyboard. Especially on displays with the smaller real estate (like working on a MacBook), navigating and editing the storyboard could be tedious.
There is a simple technique which lets us keep storyboard ViewControllers and segues between. Following one of the tutorials available is simple:
- Place UIViewController on storyboard
- Highlight its View and delete it. You should now have “hollow” ViewController.
- In identity inspector, set the custom class to name of your choice.
- Click File -> New, create new Cocoa Touch subclass of UIViewController. Don’t forget to check “Also create XIB file“. Name the class exactly as on Storyboard.
It works perfectly with Objective-C projects – iOS takes care of loading view from XIB, provided it has the exactly same name as the class. But if the class is written in Swift, all you get is black screen.
Fixing on Swift side
Apparently this smart mechanism is broken newest Xcode builds (including GM). Fortunately, simple remedies exist.
Name the XIB
Just change name of XIB file to ModuleName.ClassName.xib and view should be loaded.
Load XIB programmatically
If renaming XIBs is not appealing to you, you may keep XIB name as it is, and override loadView: method with short snippet of code:
1 2 3 |
override func loadView() { NSBundle.mainBundle().loadNibNamed("ViewController", owner: self, options: nil) } |
November 2016 Update
In Xcode 8.x/Swift 3.x naming the XIB in smart way seems to not to work anymore. Still there is programmatic way, which may be preferred as more explicit. In Swift 3, loading code would look slightly different, because of different conventions of mapping Foundation classes to Swift:
1 2 3 |
override func loadView() { Bundle.main().loadNibNamed("ViewController", owner: self, options: nil) } |
loadView is responsible for creating ViewController’s view. Override it to get control over view creation process.
Xcode 6 beta 5 update
With release of Xcode 6 beta 5, cat and mouse game continues: virtually every open source project/library written in Swift, needs to be updated. Not complaining at all, let’s see what I needed to update in example Actor library project and what is probably waiting for you to encounter.
LogicValue is now BooleanType
Swift engineers are willing to make naming consistent, and all built-in protocols shall be called something-able, -ible or -Type. If you happen to have implemented LogicValue somewhere:
- Rename it to BooleanType
- Remove getLogicValue() -> Bool function, moving its body to:
1 2 3 4 5 |
public var boolValue : Bool { get { return //... logic value of your object } } |
New BooleanType protocol defines not a function, as it was in LogicValue, but required property. Now we have a bit of extra consistency.
Optionals are no longer LogicValue (nor BooleanType)
To prevent ambiguous constructs, you can no longer use Optional value in if statement, now it needs to be explicitly compared with nil. I have used it in my functional extension to Optional, which I wrote about, and which has been rendered almost useless with Beta 5.
Elvis operator
Short ?? (two question marks) operator does the same as Optional+getOrElse() extension.
1 2 |
"123".toInt() ?? 0 // equals 123 "foo".toInt() ?? 0 // equals 0 |
Converting String to C String
Apparently String.bridgeToObjectiveC() is gone, and I needed to find other way of converting Swift’s Strings to C Strings. Existing code which creates serial dispatch queue:
1 |
dispatch_queue_create(name.bridgeToObjectiveC().UTF8String, DISPATCH_QUEUE_SERIAL) |
Now is replaced by cleaner code:
1 |
dispatch_queue_create(name.cStringUsingEncoding(NSUTF8StringEncoding)!, DISPATCH_QUEUE_SERIAL) |
Required keyword in initializers
Any subclass inheriting required initializer need to place ‘required’ keyword in front of each required initializer.
This concludes my opinionated, subjective list of breaking changes of Beta 5. I hope the more obscure ones will be found helpful!
getOrElse in Swift’s Optional
Now I couldn’t resist throwing my own two cents onto buzz around Swift language. Right now, we are on early stage of excitement, which means lots of tutorials, and emerging libraries and extensions, including a few ones which sometimes recreate features that already exist 🙂
Update: As of 4th August 2014, this article is obsolete. Swift language has been enhanced with ??
operator, which does the same.
1 2 |
<span style="color: #97bde7;"><span style="color: #75bdfa;">"123"</span><span style="color: #f5f5f5;">.</span><span style="color: #65bfdc;">toInt</span><span style="color: #f5f5f5;">() ?? </span><span style="color: #ffef5a;">0</span><span style="color: #757575;">// 123</span></span> <span style="color: #97bde7;"><span style="color: #75bdfa;">"foo"</span><span style="color: #f5f5f5;">.</span><span style="color: #65bfdc;">toInt</span><span style="color: #f5f5f5;">() ?? 0</span><span style="color: #757575;">// 0</span></span> |
I’ll leave remaining of the post for proof of that I was first 🙂
But to the point.
One of respectable Swift features are optionals. They are more important than many of you may think, so it is good to take closer look.
Optionals are wrapping value which may or may not be present. Consider an example: we have string which we want to convert to a number:
1 2 |
<span style="color: #f5f5f5;"><span style="color: #8ce46d;">var</span> maybeANumber = <span style="color: #75bdfa;">"456"</span></span> <span style="color: #f5f5f5;"><span style="color: #8ce46d;">var</span> asNumber = <span style="color: #95a6b0;">maybeANumber</span>.<span style="color: #65bfdc;">toInt</span>()</span> |
When typed in Playground, asNumber value is {Some 456}. If you really want a number, you need to unwrap it
1 |
asNumber<span style="color: #f5f5f5;">!</span> |
Forced unwrap operator, exclamation mark, will, however generate an error when input value is not a string. Eventually you end up with if-checking:
1 2 3 4 5 |
<span style="color: #f5f5f5;"><span style="color: #8ce46d;">if</span> <span style="color: #8ce46d;">let</span> actual = <span style="color: #95a6b0;">asNumber</span> {</span> <span style="color: #f5f5f5;"> actual</span> <span style="color: #f5f5f5;">} <span style="color: #8ce46d;">else</span> {</span> <span style="color: #f5f5f5;"> <span style="color: #ffef5a;">0</span></span> <span style="color: #f5f5f5;">}</span> |
Optional type implements LogicValue protocol, so any Optional variable can be used in conditional expression.
This is not satisfactory for me, though. If language is borrowing so many good parts from functional language like Scala, why not steal more? Scala’s Option type offers a number of methods, including getOrElse(default), which returns a wrapped value if it exists, or provided default otherwise.
There’s no such thing in Swift (yet). So that encouraged me to implement it by myself. Swift documentation is very high-level, with little to none specific of under-the-hood operation.
After fiddling with undocumented methods a came to my own implementation of .getOrElse() using extension:
1 2 3 4 5 6 7 8 9 |
<span style="color: #8ce46d;">extension <span style="color: #65bfdc;">Optional</span><span style="color: #f5f5f5;"> {</span></span> <span style="color: #f5f5f5;"> <span style="color: #8ce46d;">func</span> getOrElse(val:<span style="color: #dd8f47;">T</span>) -> <span style="color: #dd8f47;">T</span> {</span> <span style="color: #f5f5f5;"> <span style="color: #8ce46d;">if</span> <span style="color: #65bfdc;">getLogicValue</span>() {</span> <span style="color: #f5f5f5;"> <span style="color: #8ce46d;">return</span> <span style="color: #8ce46d;">self</span>!</span> <span style="color: #f5f5f5;"> } <span style="color: #8ce46d;">else</span> {</span> <span style="color: #f5f5f5;"> <span style="color: #8ce46d;">return</span> val</span> <span style="color: #f5f5f5;"> }</span> <span style="color: #f5f5f5;"> }</span> <span style="color: #f5f5f5;">}</span> |
You can find in in my GitHub gist. Now, instead of creating if on the very end of chained Optional calls, use nice and clean:
1 2 |
<span style="color: #97bde7;"><span style="color: #75bdfa;">"123"</span><span style="color: #f5f5f5;">.</span><span style="color: #65bfdc;">toInt</span><span style="color: #f5f5f5;">().</span>getOrElse<span style="color: #f5f5f5;">(</span><span style="color: #ffef5a;">0</span><span style="color: #f5f5f5;">) </span><span style="color: #757575;">// 123</span></span> <span style="color: #97bde7;"><span style="color: #75bdfa;">"foo"</span><span style="color: #f5f5f5;">.</span><span style="color: #65bfdc;">toInt</span><span style="color: #f5f5f5;">().</span>getOrElse<span style="color: #f5f5f5;">(</span><span style="color: #ffef5a;">0</span><span style="color: #f5f5f5;">) </span><span style="color: #757575;">// 0</span></span> |
I really hope to find such feature in Swift 1.1, otherwise it is a good start of functional extensions library for Swift.
Reboot
This is unintentional reboot of blog and website. It used to be hosted on friends server provided to me as a courtesy. It ran there for years, and suddenly stopped functioning.
The friends server has been sunset, and he forgot to notify me. Looks like I was extremely trouble-free tenant.
It is a good opportunity to start from scratch, possibly revive some posts from archives.