Migrating to Swift 4 / iOS 11

Ah, it’s migration season again, that time when all the Swifts fly to the fertile breeding grounds of version 4. ūüôā

In the past, migrating your code was a big deal when a new version of Swift was introduced – when Swift 3 came around, it seemed like every line of code had a syntax change. This time around, however, life should be a lot easier on us – in fact maybe you’ll even see this nice message during your migration:

Screenshot 2017-09-12 12.26.38.png

Here’s what Chris Lattner said about it on the Accidental Tech Podcast:

I think it’s definitely fair to say that in the Swift 1 and 2 timeframes, Swift as a language was changing really rapidly, and I could see why you’d feel like you’re on uneven footing and not really sure what the language is, much less what the idioms are. Swift 3 really is quite well baked out, and I expect that going forward the new things are going to be additive, not changing the existing patterns.

That said, as you update to Xcode 9, Swift 4 and iOS 11 you might find you need to make a few little tweaks – and not just related to Swift changes. I’ve been updating all of the code base for my book, and finding there are some repetitive tasks worth mentioning:

1. Swift 3 @objc inference.

During migration, you’ll be asked if you want to minimize @objc inference (the new Swift 4 way of doing things) or handle @objc inference the Swift 3 way:
Screenshot 2017-09-12 15.30.46.png

What’s all this about?

You can tag a Swift declaration with @objc to indicate that it should be available to Objective-C. In Swift 3 many declarations were automatically inferred to be made available to Objective-C (for example methods in a subclass of NSObject were inferred to be available to Objective-C). In Swift 4, many of these are no longer going to be inferred and the migrater will help you out by adding the @objc tag in some common places it might be needed. (A common place for example, is a method that is referenced by a #selector)

For some reason, however, despite migrating your code to manage this new state of affairs, the migrater doubles down on ensuring that there are no migration problems, and sets a new ‘Swift 3 @objc inference’ setting in your targets’ Build Settings to ‘On’, ensuring that everything works just as it did in Swift 3.

This isn’t a big problem, other than increasing your app’s binary size (about 6-8% according to the swift-evolution proposal) and load time. But – if you want your app to work just like a new Swift 4 app would, change the ‘Swift 3 @objc inference’ setting in each target’s Build Settings to ‘Default’ (or ‘Off’).

Screenshot 2017-09-12 15.38.47.png

If you check out the Xcode migration guide, @objc inference is basically all it talks about. Most other Swift changes have been add-ons and non-breaking. There are however a couple of interface issues worth mentioning.

2. Safe area guides

Xcode 9 and iOS 11 introduced safe area guides, with the idea of replacing top and bottom layout guides. This change isn’t enforced by the migrator, but if you want your app to work as a new project would, you’ll want to turn on safe area guides for your storyboards.

Open a storyboard, select a view controller, and open up the file inspector. You’ll find a new check box: “Use Safe Area Layout Guides”. Check this and immediately you’ll notice a change in the document outline of your storyboard. All of your view controllers will lose their top and bottom layout guides and be replaced by safe area guides.
safeArea.png

3. Large titles

This is another optional update, but a good idea anyway. Apple is moving towards large titles for navigation bars and has made this available to developers. To give a view controller a large title, select the first navigation bar in the navigation stack, and select ‘Prefers Large Titles’ in the attributes inspector.

largeTitles.png

This automatically sets up large titles for the whole navigation stack, though Apple suggests in many cases the large titles are more appropriate for just the initial view controller. Turn off large titles in a view controller down the line in the navigation stack, by selecting its navigation item and instead of ‘Automatic’, select ‘Never’.

largeTitlesNever.png

4. Marketing App icon

Previously we would add the huge 1024×1024 app icons for marketing purposes in iTunesConnect. Finally, Apple has united all of the app icons, and now these app icons can also be added to your app’s assets catalog.

Tagged with:
Posted in Swift

Updating push services certificate in heroku

Well, it was a year ago that I updated my app Grabble Words to use Parse Server¬†(for storing data in the cloud) via herokuapp¬†(for¬†running applications in the cloud) and mongodb¬†(database hosting service). Here‘s where I delved into some difficulties with push notifications at the time.

I’ve just received a notification from Apple reminding me that their production push services certificates only last for a year, meaning that there’s a little annual maintenance to do to keep notifications popping up on people’s devices. Otherwise how are people going to know that the other player has had their move!?

Making this update isn’t that big a job, but it can be hard to get your head back into these sorts of things. This could be a good time to record the process here…before i forget!

Basically two things need to be done:

  1. Create a new push services certificate in Apple’s member center (aka Certificates Identifiers and Profiles). What we need out of this step is a p12 file.
  2. Replace your app’s push services certificate in heroku with your new p12 file.

Fleshing these steps out a little:

Creating a new push services certificate

  1. Open Certificates, Identifiers and Profiles.
  2. Find your app in the App IDs section and select Edit.
  3. Find your app’s push services certificate that is expiring. Below it select Create Certificate.
  4. You will find instructions appear for requesting the certificate in your keychain. Follow these instructions!
  5. Once you have the request, you can upload this back in the Certificates Identifiers and Profiles page.
  6. You should now have a certificate. Download this certificate, which should be a cer file.
  7. Double click on the cer file which will install the key into your keychain.
  8. Finally, from your keychain, export this cer file, and you should have a p12 file. Hooray!

Replacing your app’s push certificate file in heroku

  1. Find the local folder for your app’s heroku file system heroku.¬†
  2. If you haven’t cloned this, or perhaps you’re on a different computer from when you cloned it originally, you’ll need to ¬†that¬†you cloned locally when you generated . ¬† (If you don‚Äôt have one, check here how to do this.

  3. From the heroku folder for your app in Terminal, log into heroku. (hopefully you still have your password!)
  4. heroku login
  5. Find your production push services certificate locally and replace it just in Finder with the p12 file you downloaded earlier.
  6. Back in Terminal, upload the updated p12 file using git. Uploading in git is called ‘pushing’, so I guess we’re pushing the push certificate…
  7. git add .
    git commit -am "replaced push services certificate"
    git push heroku master
    

That’s it! Grabble Words should now have its push services certificate safely updated in the cloud, and we have another year of game notifications, hooray!
grabotCloud

Tagged with:
Posted in Swift

Higher order functions in Swift

Higher order functions (functions that can either accept functions or closures as arguments, or return a function/closure) are mega useful for writing nice clear succinct code. You can write your own, or there are a bunch all ready to take advantage of, from the Swift standard library.

If you look around the internets the most commonly mentioned higher order functions in Swift are generally map, filter, reduce and sort (or sorted). But there are so many more to play with!

Just take¬†a look¬†at Array¬†– you will also find contains,¬†drop, first, flatMap, forEach, partition¬† and¬†split, – whaa?¬†¬†You will never need to for-in loop that array again! That said, with so many fancy tools in your arsonry, sometimes you can pull one out, realize you can’t remember how to use it and resort reinventing the wheel.

Let’s take a look at some of these more obscure higher order functions, and compare how some¬†would need to be coded in a for-in¬†or while loop, but first let’s jog our memory of the big four: map, filter, reduce and sort.

Imagine first we have an array of fruits:

var fruits = ["Banana","Pineapple","Coconut","papaya","Kiwi","Rambutan"]

map

Perform an operation on every element in an array to build another array.

eg. Let’s create another array consisting of all of the fruits in lowercase.
Instead of:

var fruitLowercase:[String] = []
for fruit in fruits {
  fruitLowercase.append(fruit.lowercased())
}
//["Banana", "Pineapple", "Coconut", "papaya", "Kiwi", "Rambutan"]

We can simply use map:

let fruitLowercase = fruits.map { $0.lowercased() }
//["Banana", "Pineapple", "Coconut", "papaya", "Kiwi", "Rambutan"]

filter

Return every element in an array that satisfies a condition.

eg. Let’s say we want all of the fruits that start with A-K.
Instead of:

var fruitAK:[String] = []
for fruit in fruits {
  if ("A"..."K").contains(fruit.characters.first!) {
      fruitAK.append(fruit)
  }
}
//["Banana", "Coconut", "Kiwi"]

We can simply use filter:

let fruitAK = fruits.filter { ("A"..."K").contains($0.characters.first!) }
//["Banana", "Coconut", "Kiwi"]

reduce

Generate a single value by performing an operation on every value of an array.

eg. Let’s say we need to know the letter count of all the fruits.
Instead of:

var totalLetters = 0
for fruit in fruits {
  totalLetters+=fruit.characters.count
}
//40

We can simply use reduce:

let totalLetters = fruits.reduce(0) {$0 + $1.characters.count}
//40

sort(sorted)

Create a sorted version of an array. You don’t need to see an example of manually sorting an array to understand how this works!

Sort an array simply by describing how you want the sort to work. You can do this simply by indicating the direction of the sort with a > or <.

var fruitSorted = fruits.sorted(by: &lt;)
//["Banana", "Coconut", "Kiwi", "Pineapple", "Rambutan", "papaya"]

Notice that “papaya” comes last, as lower case letters come after upper case letters. You may want to ignore capitalization (or localization) differences:

var fruitSorted = fruits.sorted(by: {$0.localizedLowercase &lt; $1.localizedLowercase })
//["Banana", "Coconut", "Kiwi", "papaya", "Pineapple", "Rambutan"]

I go into sorting arrays of strings in more detail here. Of course if you want to sort the array itself rather than return a sorted version of the array, you can use sort.

Of course, there’s more than just the big four – let’s take a look at other higher order functions in Array:

contains

Generate a true/false by checking if any element in your array satisfies a condition. Related to filter, but returns a Bool, rather than an array.

eg. Let’s say we need to know¬†if our fruits array contains a four letter fruit.
Instead of:

var fruitContains4Char = false
for fruit in fruits {
  if fruit.characters.count == 4 {
    fruitContains4Char = true
    break
  }
}
//true

We can simply use contains:

let fruitContains4Char = fruits.contains {$0.characters.count == 4}
//true

drop

Drops elements from your array while a condition is true, stops checking when it encounters an element that shouldn’t be dropped.

eg. Let’s say we want to drop all elements at the beginning of the array that contain the letter ‘a’.
Instead of:

var fruitDropA:[String] = fruits
while fruitDropA.count>0 && fruitDropA.first!.contains("a") {
  fruitDropA.remove(at: 0)
}
//["Coconut", "papaya", "Kiwi", "Rambutan"]

We can simply use drop:

let fruitDropA = fruits.drop { $0.contains("a") }
//["Coconut", "papaya", "Kiwi", "Rambutan"]

first

You’re probably familiar with the first property that retrieves the first element of an array, but did you know you can pass in a condition to¬†get only the first element that meets that condition?

eg. Let’s say we want the first element of the array that contains the letter ‘i’.
Instead of:

var firstFruitI:String?
for fruit in fruits {
  if fruit.contains("i") {
    firstFruitI = fruit
    break
  }
}
//Optional("Pineapple")

We can simply use first:

var firstFruitI = fruits.first { $0.contains("i") }
//Optional("Pineapple")

flatMap

Closely related to map, flatMap automatically removes any nil values from a map call, ensuring that the array returned does not contain optionals.

eg. Let’s say we have an¬†array of String values:

let numbers = ["1","3","pineapple","2"]

And we want to convert these to an Array of Int. The map function would return an Array of Optional Int, and a nil value for “pineapple” that isn’t a number:

let numbersMapped = numbers.map { Int($0) }
//[Optional(1), Optional(3), nil, Optional(2)]

That’s not what we’re after, we want an array of Int!

We could of course do this in a for loop:

var numbersMapped:[Int] = []
for number in numbers {
  if let int = Int(number) {
    numbersMapped.append(int)
  }
}
//[1, 3, 2]

But much easier using flatMap:

let numbersMapped = numbers.flatMap { Int($0) }
//[1, 3, 2]

forEach

The forEach higher order function is a cool tool for your programming arsenal Рbasically short-hand for the for-in loop.

eg. Let’s say we want¬†print the lowercase version of every fruit in our fruits array.
Instead of:

for fruit in fruits {
  print(fruit.lowercased(), terminator: " ")
}
//banana pineapple coconut papaya kiwi rambutan

We can simply use forEach:

fruits.forEach { print($0.lowercased(), terminator: " ") }
//banana pineapple coconut papaya kiwi rambutan

And three lines become one!

partition

The partition method partitions the elements of your array based on a condition. Elements that meet the condition are placed last in the array.

eg. Let’s say we want all of the¬†fruit in our fruits array that contains the letter “i” to come last. We could do this with a for-in loop:

var partitionedFruit:[String] = []
var partition = 0
for fruit in fruits {
  if fruit.contains("i") {
    partitionedFruit.append(fruit)
  } else {
    partitionedFruit.insert(fruit, at: partition)
    partition+=1
  }
}
fruits = partitionedFruit
//["Banana", "Coconut", "papaya", "Rambutan", "Pineapple", "Kiwi"]

Notice that “Kiwi” and “Pineapple”, the only elements with an “i” are placed at the end of the array. Alternatively, we can do this with just one line of code with the partition method:

fruits.partition(by: { $0.contains("i") })
//["Banana", "Rambutan", "Coconut", "papaya", "Kiwi", "Pineapple"]

Notice that this method, rather than returning a new array, actually changes the array itself. Notice also that the order of the elements within each partition changes in a somewhat random fashion.

split

You may be familiar with the components method on String, used to split a String based on a separator.

eg. Let’s say we¬†have a paragraph that we want to split into sentences. We could use the components method, checking for full-stops (aka¬†periods):

let paragraph = "I can't believe it! These higher order functions are like magic. Don't you think? Well, maybe not magic, but pretty useful all the same."

let sentences = paragraph.components(separatedBy: ".")
//["I can\'t believe it! These higher order functions are like magic",
//" Don\'t you think? Well, maybe not magic, but pretty useful all the same",
//""]

What’s with that final element though? An alternative to the components method is the split method, which accepts a separator too, but by default will omit blank elements.

To use the split method on a String, you would use it on the String.characters property, which is a String.CharacterType, which adopts the Collection protocol, giving characters access to many of the same cool higher order functions that Array has access to. Once you’ve separated String characters with split, you’ll have an array of something called a SubSequence, that you can pass in when initializing a String – you can do this on each element of your new array using the map higher order function to end up with an array of Strings.

Phew – what does that look like?

let sentencesSubsequences = paragraph.characters.split(separator: ".")
let sentences = sentencesSubsequences.map{ String($0) }
//["I can\'t believe it! These higher order functions are like magic",
//" Don\'t you think? Well, maybe not magic, but pretty useful all the same",
//""]

But wait, that ignored exclamation marks and question marks – they also define the end of a sentence. How to separate our paragraph using all three?

The split method has a fancy higher order function option as well. You can use it to divide our paragraph by full stops, exclamation marks or question marks:

let sentencesSubsequences = paragraph.characters.split { $0 == "." || $0 == "!" || $0 == "?" }
let sentences = sentencesSubsequences.map{ String($0) }
//["I can\'t believe it",
//" These higher order functions are like magic",
//" Don\'t you think",
//" Well, maybe not magic, but pretty useful all the same"]

Well that’s it! I hope next time you need to perform some magic on an array, you too might remember and take advantage of one of these higher order functions, keep your code nice, pretty and succinct and remember that you don’t need to reinvent the wheel!

Tagged with:
Posted in Swift

Get started with iOS in Swift today

Grummitt-iOS-HIAre you thinking about getting into iOS in Swift, and are looking for an all-in-one guide?

I have just the book for you.

iOS Development with Swift¬†brings you into the world of developing iOS apps, using Apple’s Swift programming language. No prior experience with¬†Swift required,¬†as we explore what’s new and exciting about this language in a lightning tour.

After covering some basics of iOS, we will build up an app from idea through to publishing our app on the App Store. On the way we’ll look at solving common iOS problems, laying out your app interface in code or using a storyboard, structuring your code in iOS, working with data on the device and in iCloud, best practices and what to do when things don’t go to plan.

Start learning iOS today! Look for your 42% off discount code below:

Tagged with:
Posted in Swift

Size classes in Xcode 8

More devices, split view controllers (introduced in iOS 8), slide over and split view multitasking modes (introduced in iOS 9) have all made adjusting a layout to its environment more and more complex.

ch7_SizeClasses.png

Interested to know about Size classes in Interface Builder in Xcode 8?

Check out my article on Medium here.

 

Tagged with: ,
Posted in Swift

Sprite Kit Easing in Swift

It¬†really is¬†surprising that SpriteKit,¬†Apple’s framework for building 2D games doesn’t have better easing algorithms available.

I’ve just updated my solution, SpriteKitEasingSwift, to Swift 3, and added Carthage support. Here it is at github and CocoaPods.

easing.gif

Kudos to buddingmonkey who built the Objective-C library this framework was originally based on.

 

Tagged with:
Posted in Swift

Xcode Keyboard Shortcut for CamelCase!

Sometimes it can be a pain moving around code in Xcode especially with long method and property names. Then I discovered an Xcode keyboard shortcut that rocks Рmove back and forward through camel case sub-words!

Use¬†Control‚Üí¬†and¬†Control‚Üź to skip through camel case. Hold down shift to highlight as you go:

camelright.gif

You may be wondering why this isn’t working on your machine – this does take a tweak to achieve, as the Xcode shortcut is usually¬†usurped by an OS keyboard shortcut preference to move through full screen windows.

If you can handle removing full screen¬†keyboard shortcuts to go left and right (you can just as easily swipe¬†four keys on the trackpad) then open System Preferences > Keyboard > Shortcuts and deactivate the ‘Move left a space’ and ‘Move right a space’ shortcuts:

Screenshot 2016-09-30 17.18.51.png

Alernatively, if you’re not keen on losing those shortcuts, you can always change the shortcut in Xcode – just look for Move Subword Back and MoveSubword Forward in Xcode Key Bindings Preferences.

Tagged with: ,
Posted in Swift