Harry Richardson

My New Hackintosh With Clover

| Comments

It’s that time when I decide to buy a new hard drive and install a new Hackintosh on my computer. I just bought a Samsung 850 500GB SSD. This will now house OS X rather than the 5 year old 64GB SSD it was on previously. I was struggling with the 64GB I had previously - it just wasn’t enough, and I constantly had to remove things to make space.

This time around I’ve also decided to try a new boot loader, Clover. Not much reason for this other than it’s new and meant to be “the way forward”. It’s also compatible with UEFI (which my motherboard, the Gigabyte Z77-UD3H, supports).

I used this website as a general guide.

It’s a great, general guide for installing OS X with Clover. Of course, each system is unique and has its own issues.

Here are the specs of my system in full:

  • Intel i5 3570K
  • Gigabyte Z77-UD3H (can’t remember which revision)
  • XFX Radeon 6870

These three are really the only important parts, as far as I know.

I made a silly mistake when installing Clover on my installation USB drive, and that was selecting my Macbook Air’s boot hard drive instead… Yeah, smooth. So I had to spend 15 minutes making sure I cleaned all the Clover files - there was the risk that Clover would alter my actual Mac’s boot drive.

The other main thing I did differently to Tony’s guide above was to make sure I disabled all my other hard drives in the BIOS - I don’t know about OS X, but Windows loves (loved?) to install files on partitions it’s not meant to. Anyway, to be safe, I disabled the rest and everything went smoothly.

Booting into OS X for the first time showed me a few issues: only one monitor was working, and I had no sound or ethernet connectivity. On the upside, I had these issues with my last installation and I kept instructions to my future self on how to resolve them. On the downside, the graphics instructions told me to alter my Chameleon plist file… well, I’m not using Chameleon anymore! So I had to find the necessary file to fix up Clover.

For those wondering, here are the kexts/instructions I went with for graphics, audio, and network:

  • Installed ALXEthernet.kext 1.0.2 via MultiBeast
  • Installed AppleHDADisabler.kext (I don’t remember where I got this kext from originally, sorry)
  • Installed VoodooHDA.kext (also don’t remember where I found this one)
  • Changed VideoPorts=4 and FBName=gabba in the Clover config.plist of EFI

I hate OS X mouse acceleration so I installed a driver for my simple Microsoft Mouse. I believe I just searched ‘Microsoft Intellipoint 8.2’. Works perfectly. Currently, I have to manually launch the preferences pane for this to work every time OS X launches - there is a way to automate this, I’ve just been lazy.

I’m pretty happy with the setup. I think in the future I will go with motherboard and graphics card that are even more compatible. This installation isn’t perfect because there are times where the audio will no longer work after waking up from sleep; I would say that’s a minor problem though. So far no kernel panics or any other major problems.

Next on the list: format one of my storage drives to be exFAT because I don’t trust any of the NTFS OS X drivers after one wiped one of my hard drives. Thanks, Paragon.

How I Optimise Table View Performance With Dynamic Cell Heights

| Comments

Dynamic cell heights in UITableView have put a big spanner in the works in terms of performance. You can’t simply return an arbitrary height under heightForRowAtIndexPath and assume everything will work. If you have text in your cell that could be 1 line or 10 lines, your cells need to have a dynamic height. There are a couple of ways to measure this height. I’ll get into that shortly. Measuring cell heights can also be a relatively slow process, so I’ll also go into optimisation techniques to achieve the all-important 60 frames-per-second that everyone strives for.

To jump straight to a project with all the final source code, go here

The Basics

With auto-layout being pushed by Apple as the primary method of laying out your views, it certainly makes sense to measure cells using it as well. To do this you would create a method similar to the following:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
- (CGFloat)heightForRowWithModel:(id)model {
      // 1  
    static Cell *prototypeCell = nil;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        prototypeCell = [self.tableView dequeueReusableCellWithIdentifier:CellIdentifier];
    });

    // 2
    [prototypeCell configureForHeightWithModel:model];
    // 3
    prototypeCell.bounds = CGRectMake(0.0f, 0.0f, CGRectGetWidth(self.tableView.bounds), CGRectGetHeight(prototypeCell.bounds));
    [prototypeCell layoutIfNeeded];
    // 4
    CGSize size = [prototypeCell.contentView systemLayoutSizeFittingSize:UILayoutFittingCompressedSize];
    CGFloat actualHeight = size.height + 1;
    return actualHeight;
}

There’s a couple of things to mention here:

  1. There is an offscreen cell that I’m using to measure heights with. There would need to be one of these for each identifier/model combination.
  2. The cell is configured using a height-specific method; this is so nothing is set that doesn’t need to be set. If you know the size of an image view, you don’t need to load the image. Stick with what can change, such as multi-line labels.
  3. Set the size of the cell itself: remember, the cell is offscreen, but we need it to be the size that it will be when on the screen. For example, if the user is in landscape mode, the width of the cell needs to be altered accordingly.
  4. Call systemLayoutSizeFittingSize method on the contentView view on the cell. Doing this at the cell level won’t layout the content view correctly. Do it on the content view and then add the +1 to get the size of the cell (remember, the content view height is 1 less than the cell).

In the Cell class itself the layoutSubViews method needs to be overridden in a way similar to this:

1
2
3
4
5
6
7
8
- (void)layoutSubviews {
    [super layoutSubviews];

    [self.contentView layoutIfNeeded];

    // All labels need to have their preferredMaxLayoutWidth set (if iOS 7 is being supported)
    self.label.preferredMaxLayoutWidth = CGRectGetWidth(self.label.frame);
}

The contentView is also laid out because we changed the bounds on Cell and now we need to force the layout on contentView. Of course we also need to set the preferredMaxLayoutWidth on label.

This is pretty basic stuff when it comes to dynamic cell heights in iOS 7 and above. Notice how I haven’t done any optimisations at all, including implementing estimatedHeightForRowAtIndexPath. This is intentional, I wanted to keep the part about measuring totally separate to everything else.

Optimisations

So, the biggest optimisation is, of course, implementing estimatedHeightForRowAtIndexPath. Most people recommend not doing any calculations in this method as it will be called on every row in the table view. Remember, heightForRowAtIndexPath is only called for the visible rows.

Performance at this point may be enough. We’re trying to get as close to 60 FPS while scrolling on old devices (for me, this is the iPhone 4S and iPad Mini) as possible. If you’re not hitting that magical 60 FPS, it’s worth continuing the optimisation.

The next step is to cache cell heights for your table view.

First of all, if your models have a tendency to change, it would be a good idea to override hash and isEqual. To explain: the idea is that we use the model’s hash as a key in a dictionary, and the cell height as the value. If your data is changing throughout, that cached height needs to change as well because the data could affect it.

It’s actually quite easy to implement at this point, a mutable dictionary property needs to be added to the class, and then in the heightForRowWithModel method, a few lines need to be added. The method will now become:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
- (CGFloat)heightForRowWithModel:(id)model {
    NSNumber *key = [model hash];

    NSNumber *height = self.cachedHeights[key];
    if (height) {
        return [height floatValue];
    }

    static Cell *prototypeCell = nil;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        prototypeCell = [self.tableView dequeueReusableCellWithIdentifier:CellIdentifier];
    });

    [prototypeCell configureForHeightWithModel:model];
    prototypeCell.bounds = CGRectMake(0.0f, 0.0f, CGRectGetWidth(self.tableView.bounds), CGRectGetHeight(prototypeCell.bounds));
    [prototypeCell layoutIfNeeded];
    CGSize size = [prototypeCell.contentView systemLayoutSizeFittingSize:UILayoutFittingCompressedSize];
    CGFloat actualHeight = size.height + 1;
    self.cachedHeights[key] = @(actualHeight);
    return actualHeight;
}

This data can be persisted in any way you see fit; it doesn’t have to just be a dictionary. I will point something out though: the cache will either need to be erased when the device orientation changes, or when the cell bounds change. In my own apps I opt to just override willRotateToInterfaceOrientation and erase the cache there. It’s entirely up to you how you deal with this. You could even cache the heights for each width of the table view - for example, have a dictionary of dictionaries, with the outer dictionary’s keys being the table view width.

The next step is to re-implement estimatedHeightForRowAtIndexPath with our new cached values. We no longer need to return an arbitrary value as we now have a cached value available to us. This won’t necessarily increase performance, but given that there will occasionally be a slight “jump” when slowly scrolling a table view that hasn’t completely measured all row heights, this is great for user experience.

Here’s an example of the method implementation:

1
2
3
4
5
6
7
8
9
- (CGFloat)estimatedHeightForRowWithModel:(id)model {
    NSNumber *key = [model hash];
    NSNumber *height = self.cachedHeights[key];
    if (height) {
        return [height floatValue];
    } else {
        return 70.0f;
    }
}

Easy!

What if you still haven’t reached 60 FPS while scrolling? Well, there’s still more we can do!

One of the major complaints of auto-layout is that it can be pretty slow when laying out a lot of views - exactly what we’re doing when scrolling. Given that we only want to layout for height, laying out the entire content view of a cell maybe slightly overkill. So what to do instead? We go old school! We can still use auto-layout on the cell, but when it comes to measuring, the text should be measured manually, and all constraints added in and used. If I’ve created the cell in a XIB, I’ll generally add an IBOutlet for each height-related constraint and use the constant property instead of using a fixed value in code. After all, I may decide to change the margin sizes in the future.

The biggest problem doing this is with measuring text. I created a category on NSString that takes care of this for me. Here’s the implementation:

1
2
3
4
5
6
7
8
9
10
- (CGSize)sizeConstrainedToSize:(CGSize)constrainedSize usingFont:(UIFont *)font withOptions:(NSStringDrawingOptions)options lineBreakMode:(NSLineBreakMode)lineBreakMode {
    NSMutableParagraphStyle *paragraphStyle = [[NSMutableParagraphStyle alloc] init];
    paragraphStyle.lineBreakMode = lineBreakMode;

    NSAttributedString *attributedText = [[NSAttributedString alloc] initWithString:self attributes:@{NSFontAttributeName: font, NSParagraphStyleAttributeName: paragraphStyle}];
    CGRect rect = [attributedText boundingRectWithSize:constrainedSize options:options context:nil];
    CGSize textSize = CGSizeMake(ceilf(rect.size.width), ceilf(rect.size.height));

    return textSize;
}

What this is doing is converting the NSString into an NSAttributedString to do its measuring. If I’m honest I’m not actually sure if this is the most performant way of measuring text, but so far it’s achieved everything I need so I’ve not had to look for alternative solutions.

This is used with the following method call:

1
2
3
4
[text sizeConstrainedToSize:CGSizeMake(label.frame.size.width, CGFLOAT_MAX)
                                    usingFont:label.font
                                  withOptions:options
                                lineBreakMode:NSLineBreakByWordWrapping].height;

There will obviously be times where your UILabel will have a maxNumberOfLines that isn’t 0. In this case the CGFLOAT_MAX should be changed with a value that is similar to the following:

1
ceilf(label.font.lineHeight * label.numberOfLines);

There are plenty of other optimisations you can do, such as reducing the number of shadows in a cell, but these kind of things aren’t related to cells with dynamic heights so I won’t include them here.

To view the code for this post please go here

Intimacy

| Comments

I released a small app called Intimacy a short time ago. It took me a whole 8 hours to complete, including design, development, and the submission process.

Why?

I haven’t released anything under my name for a long time. That’s not because I haven’t been building, but I have that problem of doing 80% of a project and then stopping. So instead, I decided to build something small - something that would take me a single day (just about) to complete. I, along with a bunch of other people, had read the New York Times article about falling in love with anyone. The idea is that by sharing the answers to 36 questions with a partner, you become more vulnerable with them, thereby possibly increasing intimacy. I figured it’d make a cool, but very small, app.

I made it to be a timed challenge: I started making Diving Buddy almost two years ago, and looking at the code makes me cry a little on the inside. Sure, it works, but it’s overly-complicated and a chore to read. So I set myself a target of making Intimacy code-complete in a day.

How does the 8 hours break down?

It took me about 5 hours to write all the code for Intimacy. I knew what I wanted to do; I Googled websites for pastel-based colour schemes, picked a colour scheme that seemed appropriate, and got to work. Other than the 36 (37 with the eye-staring) questions, I added a few little extras: social network sharing, listing my other apps in Settings, links and short descriptions behind the idea, and timers for the timer questions. The app is fully auto-layouted, meaning it happily works on both iPhone and iPad, in portrait and landscape. There is one thing it doesn’t do with regards to layout, and that’s dynamic text. Perhaps I’ll do it in an update!

Approximately 90 minutes was spent on the icon. I admit, design isn’t my strong suit, and I actually asked a colleague, Bauke, for ideas on this. In under a minute he had sketched out an icon that later became the official Intimacy icon. I think it’s absolutely brilliant: it’s two question marks facing each other in the shape of a heart. Despite Bauke sketching out the idea in under a minute, it still took me an age to draw it out all out. I, of course, used App Icon Template to output all the necessary icon sizes.

The remaining time was spent creating the provisioning profiles, writing descriptions, creating screenshots, and submitting to the store.

Other stuff

I had wanted to get the app out for Valentines Day, but unfortunately I ran into some submission problems. I got rejected for not having the correct age rating - that was my fault, apparently dating apps need to have a mature rating. Makes sense I suppose!

The Apps I Use: Spotify

| Comments

Spotify is, without a doubt, my most used app. I listen to music constantly throughout the day - on my phone or the desktop application. Obviously my commute is strictly on the phone. I have had a premium subscription to Spotify for about 4 years, so I think Spotify in general is great (I wouldn’t be using it for so long otherwise!); however, as you are about to find out, I do have a few qualms with the iPhone app.

Let’s talk about the design:

I like the dark colour scheme and overall aesthetics of the app - it’s certainly easy on the eyes. From a UX perspective, however, I feel there are some major issues. The biggest and most obvious is the hamburger menu! It doesn’t add anything to the experience - it only takes away. Surely Spotify have analytics on what sections the user visits most? Do they look at the ‘Activity’ section as much as the ‘Your Music’ section? I wouldn’t have thought so (could be wrong, of course). If so, move it away. The other thing that’s annoying with these hamburger menus is the depth of your navigation stack; it’s so easy to be browsing one of your playlists, tap a song’s details, go to the album, then to the artist, then elsewhere, and suddenly you’re 8 levels down and you realise you want to search something else. In order to do that you have to go back those 8 times, then tap the hamburger icon, and finally you’re allowed to search. It’s incredibly frustrating. You’ve also lost your navigation stack where you were before. I wouldn’t say this is an enjoyable experience!

Since writing the initial draft to this post, the desktop application has been updated, and the first thing I noticed was that the left menu has been stripped down. Many of the options have been moved - either under different headings, or just moved elsewhere. This is great, and I really hope the iPhone application follows suit.

OK, onto functionality:

I like a lot of things about the app - you can do a lot with it. Much of what you can do on the desktop app you can also do on the mobile app. You can even control what your desktop app is playing straight from the mobile app! Or continue playing what you were listening to elsewhere - I like that. Continuity is great, and I’m yet to see any bugs with this particular feature. It can’t have been easy to implement, and yet it feels so seamless.

There are a few bugs which continue to annoy me. When I first started writing this post (a good few months ago, I apologise) there were a number of offline play bugs; there were bugs that would show their ugly face when you tried to queue a song. Most of these have been fixed, thankfully. This is good news. The bad news is that every so often when I sync up my playlists from my computer, some songs fail to transfer - they are essentially broken unless I completely delete the app and start all over again. Annoyingly, this seems to be random, and doesn’t always happen immediately. I am unable to queue the songs. They look as if they would play fine (the green synced arrow is there). But they do not, and this is incredibly frustrating. There are even other occasions where a song is greyed out, but the synced arrow is visible. I think overall, this is one of those things that I’m currently putting up with because I have 600 songs in this playlist and 1 or 2 (or 23, I just counted) not working doesn’t quite make me want to leave Spotify.

Finally, a positive point - which mostly offsets the previous point - is that Spotify’s release cycle is excellent. For the last few months it’s been at least one update per month. Not all large companies are so agile, so this is really good news.

The Apps I Use: Evernote

| Comments

I use Evernote for almost all of my note taking - especially on desktop. I find the Mac app to be really great: it’s well designed, easy-to-use, and I’ve had few to no bugs with it.

With that said, I find the iOS app to be lacking in a number of areas that the Mac app just happens to excel at. On the Mac app there is a sidebar with all of your shortcuts, and a vertical list for access to Notes, Notesbooks, Tags etc. This is great - it is always visible, no matter where you are in the app. You can easily go from one part of the app immediately to another part.

On the iOS app everything happens on the main screen, and I find it just so… cluttered and noisy. It’s completely full to the brim with stuff and, honestly, it’s quite overwhelming. There’s just nothing to separate the different parts of the product. The tabbar is one of the best controls in iOS - especially for these products that can have so much going on. It allows the user to easily see where they are and where they can go to, from a very quick glance. It would also have the added benefit of de-cluttering that front view in the app.

Another thing I like about the Mac app - and don’t like about the iOS app - is the complete lack of transition animations. Sure, it’s not fancy, but it works damn well. I’m not sure if this is just me, but I love it when a view-transition gives you context as to what’s going on. In an iOS app, a modal transition (pushing the view controller up from the bottom) means something the user has to focus on (the tabbar is hidden, for example). Contrast this to a navigation controller push, which allows the user to still navigate to other parts of the app via the tabbar, and go back through the navigation stack. So what I find quite irritating in the Evernote iOS app is that the Shortcuts and Notebooks view controllers use a custom push transition - along with different look and colour scheme on the navigation bar - to that of the Notes view controller (which is a standard navigation push transition).

The good parts: I really like the note editing view - I find the toolbar easy to use and all icons natural; I haven’t experienced any bugs at all anywhere within the app; creating notes is front and centre on the main view, which is great, and finally, the number of settings available to the user is impressive. I’m not a huge fan of having a bunch of different themes, but I can appreciate that a lot of users would be, especially in something like a note-taking app.

My overall feeling for the Evernote iOS app is that it’s just trying too hard. I still find Evernote, in general, really great to use, I just find myself using the basic Notes app on my phone because I can very quickly and easily create a note - I don’t have to hack my way through the green jungle just to be able to write something.

The Apps I Use: CityMapper

| Comments

I use CityMapper at least twice a day, every weekday. Once in the morning to check my journey is all good and no delays. Second, in the evening, on the way home from work, to check there are no delays! It’s an invaluable tool, and while not perfect, every time I’ve e-mailed the developers with a suggestion they have been extremely polite and taken it on-board.

CityMapper takes every bit of data they can get their hands on and then uses it to provide the user with information on how to get from A to B - whether it’s fastest to take a single tube, a bus and a tube, or simply just to walk.

One of the things I really like about CityMapper is how chilled-out everything is. The developers have taken great lengths to provide the user with a genuinely fun experience for something that could quite easily be boring and monotonous. For example, when searching for the fastest route somewhere, the app may tell you the fastest way is actually via catapult - and by choosing the option you get to see a short animation of the catapult in motion. The update notes are also usually filled with humour; sure, they provide the information you need to know, but the developers do it in a way that’s interesting and enjoyable.

There are certainly areas for improvement: for example, change times within stations are not always accurate. It may say 1 minute to change from Circle to Piccadilly, when in fact it would take at least 5 minutes. Not always a big problem for most journeys, but for those really tight ones, it matters. This was one of the points I e-mailed the developers about and they replied incredibly quickly, letting me know it would be in the next release (and it was). I have a feeling live traffic data is not being used in the app, but from what I can tell, bus and car journey listed times do change throughout the day. Something is obviously going on under the covers - perhaps the developers took the approach of using the time of day to alter a base duration.

Another area I’d like to see improved would be automatic caching of recent routes. Recent routes only save as destinations, not including starting points. I would much prefer the whole route was saved, and then cached, because a lot of the time when I want to check my route I am on the tube and have no signal!

CityMapper is a wonderful app with a great design and colour scheme. It provides accurate, useful information. Navigation (of the app) is simple and natural. There are very few downsides within the app, and I’ve so far not encountered any serious bugs. When I talk to friends and colleagues about the apps they use and enjoy, CityMapper is almost always mentioned - it is that prominent in people’s minds.

The Apps I Use

| Comments

I was recently thinking about the apps I use. I found it interesting to think that I have a go-to app for a particular interest, need, or desire. I don’t use two weather apps, or two note-taking apps. That’d be redundant; instead, I have one app that I like the most of the ones I have tried and stick with it.

This probably sounds quite straightforward - and it really is - but it lead me to think about why I use these apps. Why did I choose Day One as my journal app rather than the other dozen or so that are out there? Why BBC Weather, which is a free app, when I’ve paid for other weather apps? They must be doing something that I found to be better than the others. Day One is not a unique concept - people have been keeping journals for a very long time, and yet the developers implemented the idea in such a way that I felt beat all the others.

So I’m going to write a few blog posts about the apps I use - what I like about them, what I dislike. I may also write about the competition and why I didn’t choose them. I think it’ll be good to really pay attention to these apps, focus on why I enjoy using them, and perhaps I can learn from them and use what I’ve learned in my own apps.

Of course, it’s not just about the app itself which may cause it to “win” - perhaps the marketing is better, perhaps it syncs to another program that I use. There’s even the possibility that the company developed a desktop version of the application! I’ll try and pay attention to these things as well.

Here’s what I’ve covered so far:

  1. CityMapper
  2. Evernote
  3. Spotify

Introducing Diving Buddy Lite

| Comments

I made a post over a month ago about Diving Buddy going freemium - it took a long time, but Diving Buddy Lite is now officially released in the app store.

I ended up releasing an entirely new app for the lite version - this is because it would’ve been difficult adding in the In-App Purchases to an app that has already been selling on the app store. This way, a user can either purchase the full version of Diving Buddy, or download the lite (free) version and unlock some of the calculators to get the same features - for the same price.

I’m really pleased with this release - it’s something I’ve been wanting to add in for a long time. The app has been in the store for less than a week and the daily downloads are quite astonishing, particularly as I’ve done no marketing for it. Next: the Android version!

Here is the iTunes link to Diving Buddy Lite. I hope you like it.

External Parameter Names in Swift

| Comments

I really like how Apple have implemented parameter names in Swift. In Objective-C you’re very much tied in to type out every parameter as they’re part of the method identifier. Methods are very verbose, and I have actually come to like that (from a C# background, it took some time to get used to at first).

In Swift, parameters have their internal name - i.e., what you call the parameter within the method itself. When calling the method, these names are optional. As the developer you could have a method such as:

1
2
3
func greet(name : String) -> String {
     return “Hello, “ + name
}

Now call it with var greeting = greet(“Harry”). Very easy. Or you could force developers to specify the parameter name. In the previous example, this would be changed to:

func greet(name name : String) -> String

Which is essentially func greet(externalParameterName internalParameterName : String) -> String.

Interestingly, if you set the external name to the same as the internal name, the compiler will warn you of this, and say you can make it look much better by simply giving the internal name a prefix of #.

Sometimes you may also see the underscore (_) character in Swift methods. When creating a method with a parameter that has a default value, Swift will automatically give it an external parameter name. You can override this behaviour by prefixing the parameter name with an underscore. For example:

1
2
3
func join(s1: String, s2: String, joiner: String = " ") -> String {
    return s1 + joiner + s2
}

To call this method you would have to type something like let fullName = join("Harry", "Richardson", joiner: "-"). You may not want to have to type joiner in the method call though! You may be stuck in your ways and love the old non-Objective-C way of doing things. In which case, you would re-write that method signature as func join(s1: String, s2 : String, _ joiner : String = " ") -> String - notice the underscore just before the third parameter. You can now call the method as let fullName = join("Harry", "Richardson", "-").

You will see external parameter names being used in Objective-C APIs all the time.

Optionals in Swift

| Comments

Optionals are a concept that isn’t in Objective-C, which makes them instantly cool already (and that’s disregarding the usefulness of these, as I’ll go into shortly).

What are optionals?

An optional is a variable with a question-mark (?) on the end of it. It means that the variable has a value, and it’s X, or that there isn’t a value at all. If you’re from a C# background, you’ll know of the Nullable concept - I believe it’s pretty similar to that. What’s different is that if a variable isn’t an optional it must have a value. The compiler won’t allow you to set it to nil.

Interestingly, you can use optionals on all types, including primitives and structs, as well as classes, of course.

Under the covers, optionals are just an enum - the question-mark is simply syntactic sugar added by Apple to make them easier to use:

1
2
3
4
enum OptionalValue<T> {
  case None
  case Some(T)
}

When to use optionals?

I guess the biggest use for them is that they don’t have to be initialised in a class. Take this example.

1
2
3
class TestClass {
     var tableView : UITableView = UITableView()
}

You’ve just instantiated that tableView property because if you don’t the compiler gives you an error. How frustrating! Instead, you can just do:

1
2
3
class TestClass {
     var tableView : UITableView?
}

This essentially says that the tableView can be nil - it has no value at all. If you were to call tableView?.reloadData() the reloadData method would be ignored if the tableView is nil.

Another good use-case: delegates! One of the most popular design patterns in Cocoa, you can now basically just do delegate?.didDoSomething() rather than checking if the delegate exists and if it responds to the selector. Amazing.

One thing that should be remembered with Swift is that it aims to be an extremely safe language, meaning it will try and warn you, the developer, at compile time if and when you are doing something that could break. This is the whole point of optionals.

Unwrapping optionals

There is another character that we need to be aware of when working with optionals, and that’s !. It’s used in the same places as ? but it’s to be used to unwrap optionals - it exposes the underlying value that the optional is holding. If you know absolutely 100% that the optional is not going to be nil (i.e., it has a value) then you can straight up unwrap it. If not, unwrapping it in an if-statement is safest. To do this you would do something like the following:

1
2
3
4
5
if let unwrappedValue = optionalValue {
  // optionalValue wasn't nil, and now we have unwrappedValue which is definitely not nil - we can use it safely 
} else {
  // the optional is nil
}