flatMap vs compactMap

In Swift 4.1, the flatMap function was divided into two functions. One kept the same name:

flatMap

This method flattens a sequence.

Let’s say we have a two-dimensional array:

let a = [[0,1,2],[3,4,5]]

We can use the flatMap higher order function to ‘flatten’ this into a one-dimensional array:

let b = a.flatMap{$0} //b = [0, 1, 2, 3, 4, 5]

You could flatten a dictionary too – you would just need to specify what you want to flatten the values. Let’s say we have a dictionary of animals, divided into classes:

let animals = [
  "Mammals":["cat", "dog", "alpaca"],
  "Reptiles":["lizard", "goanna", "snake"]
]

You could flatten this into a one-dimensional array of all animals, ignoring class:

let flatAnimals = animals.values.flatMap{$0}
flatAnimals //["lizard", "goanna", "snake", "cat", "dog", "alpaca"]

compactMap

In Swift 4.1, the second function of flatMap is now called compactMap. The compactMap higher order function will remove any nil elements from a sequence. Imagine you have an array of Int optionals that contains both Ints and nil:

let numbers:[Int?] = [0, nil, 1, nil, nil, 2]

You can use the compactMap method to remove any nil values from this array:

let compactNumbers = numbers.compactMap{$0}
compactNumbers  //[0, 1, 2]

You can compact a dictionary too but you’ll need to use the filter method. Here’s a dictionary with String optional values:

let snakes:[String:String?] = ["A":"Anaconda", "B":nil, "C":"Cobra"]

You can use the filter method to

let compactSnakes = snakes.filter {$0.value != nil }
compactSnakes //["A": "Anaconda", "C": "Cobra"]

You might be wondering why the compactMap function doesn’t accomodate dictionary. This will be addressed in Swift 5 with the new compactMapValues function:

let compactSnakes = snakes.compactMapValues {$0}

Here‘s the Swift evolution proposal for compactMapValues.

Tagged with: , ,
Posted in Swift

Xcode 10 keyboard shortcuts cheat sheet

Getting adjusted to keyboard shortcuts takes some work, but they can boost your productivity significantly. I’ve put together a cheat sheet for a number of frequently used keyboard shortcuts in Xcode 10. I recommend you print it out, stick it on your wall, and in no time you’ll have them committed to memory!

keyboardShortcuts.png

Tagged with: ,
Posted in Swift

The Mysterious Case of the Status Bar

All I wanted was two things for my status bar:

  • I wanted it to have white text by default as it was going to be on a dark background
  • I wanted to be able to hide it temporarily every now and again.

Straightforward right?

Not so much… Let’s take a look at the case.

So if you hunt around, there are so many ways to manipulate the status bar, let’s take a look at some:

General Settings of your Target

In the General tab for the preferences for your project’s target, you’ll find two fields that adjust the default behaviour of your status bar :

  • Status Bar Style – choose between Light (i.e. light text) or Default (i.e. dark text)
  • Hide status bar – a checkbox.

TargetSettings.png

These fields are derived from the info plist, which would be an alternative approach for adjusting these fields:

Info plist fields

If you’re using info.plist to adjust the default behaviour of your status bar, you’ll want to add rows for:

  • Status bar is initially hidden (UIStatusBarHidden) – Choose from YES or NO.
  • Status bar style (UIStatusBarStyle). Choose from either:
    • default (UIStatusBarStyleDefault)
    • light (UIStatusBarStyleLightContent)

Ignore that Xcode wants you to choose between Opaque black style and Transparent black style (alpha of 0.5). These are deprecated styles, it appears as though no-one told the property list editor that yet.

InfoPlistSettings.png

You may have noticed I have another status bar related row set up in the info.plist – another Boolean property called View controller-based status bar appearance – I’ll come back to this one in a moment.

So they are the ways to set up the defaults for the status bar style and whether it is hidden or not.

But how about if you want to temporarily change these defaults?

If you look around the internets, you’ll see two alternative solutions mentioned:

Set properties on the AppDelegate

Some will suggest you to set properties on the AppDelegate:

UIApplication.shared.statusBarStyle = .default //Set Style
UIApplication.shared.isStatusBarHidden = false //Set if hidden

These could be set for example in the didFinishLaunchingWithOptions method of your app’s AppDelegate, or anywhere you like really – for example, if you wanted to change this temporarily for a view controller you could call this in the viewDidAppear and viewDidDisappear methods.

Sounds great, right? Just call a method to update the status bar, easy.

Oh wait, sorry. I forgot to mention – the isStatusBarHidden and statusBarStyle properties were deprecated in iOS 9. Bah!

Screenshot 2018-08-23 13.14.50.png

Let’s take a look at the view controller properties that Xcode are suggesting:

Override properties in your view controller classes

Within your view controller classes, you can override the prefersStatusBarHidden and preferredStatusBarStyle properties:

override var prefersStatusBarHidden: Bool {
  return true
}
override var preferredStatusBarStyle: UIStatusBarStyle {
  return .lightContent
}

These methods return values by default (prefersStatusBarHidden = false, preferredStatusBarStyle = .default), so if you change either of these default values, when the user navigates to another view controller, if the new view controller doesn’t have its own implementation of these methods, it will revert to these defaults. This is a difference in behavior to setting properties on the appdelegate, which changes them for the duration of your app, well, at least until you specifically request they change again.

Changing mid view controller

By the way, you can use these properties to make this change mid view controller too. Just set up a variable, let’s call it statusBarHidden, to contain the current preference for the status bar.
We could then return this variable in the view controller property prefersStatusBarHidden:

var statusBarHidden = true
override var prefersStatusBarHidden: Bool {
  return statusBarHidden
}

Now if we change the statusBarHidden property, nothing will happen yet. We need to tell the system that we want the status bar to change. We can do this in a property observer:

var statusBarHidden = true {
  didSet(newValue) {
    setNeedsStatusBarAppearanceUpdate()
  }
}

Now we should be able to change the statusBarHidden property, and the status bar will automatically update. For example, we could have a button that toggles the status bar, connected to an IBAction:

@IBAction func toggleStatusBar(_ sender: Any) {
  statusBarHidden.toggle()
  //If you're pre Swift 4.2, use: statusBarHidden = !statusBarHidden
}

What do we have so far?

So, let’s summarize what we’ve got:

  • General Settings of your Target / Info plist fields
  • Set properties on the AppDelegate (deprecated, remember)
  • Override properties in your view controller classes

Here’s the stinger in the tail. Remember that View controller-based status bar appearance property we saw in the info plist file? Which options are available to us, depends on what we choose in this field:

If we have View controller-based status bar appearance set to NO, we can make a change to the default status bar in the general settings or info plist. We could also set properties on the AppDelegate, but don’t forget, that property is deprecated.

If we have View controller-based status bar appearance set to YES, we can override properties in our view controller classes.

Back to the problem…

Remember my original problem?

  • “…white text by default…” – the obvious way to do this would be change defaults in General Settings / Info.plist
  • “…hide it temporarily…” – the obvious way to do this would be simply to override properties in a view controller class.

Only problem is, these two solutions are mutually exclusive, I can’t set View controller-based status bar appearance to both NO and YES… Setting properties on AppDelegate would have been a good solution to this problem, but this technique is deprecated.

Which leaves me with the only solution of setting the style of the status bar on each view controller. A bit of a pain!

You could set up a subclass of UIViewController that manages this for you, and then every ViewController in your project would then have to implement this class…

class UIViewControllerWithLightStatusBar:UIViewController {
  override var preferredStatusBarStyle: UIStatusBarStyle {
    return UIStatusBarStyle.lightContent
  }
}
...
class ViewController: UIViewControllerWithLightStatusBar {
...

But this is still an inconvenience and feels a little hacky. If anyone knows of a reliable and safe way to change the status bar behavior project-wide while having View controller-based status bar appearance set to YES, I’m interested to hear it!

Navigation Controllers

I’m afraid we’re not done on the mysterious case of status bars – embed your view controller in a navigation controller, and if you have View controller-based status bar appearance set to YES, suddenly the navigation controller now takes over control of the style of the status bar, and your view controller’s preferredStatusBarStyle property will be ignored.

If you want to adjust the style of the status bar in a navigation controller, you’ll need to do this in the navigation bar’s style property, either in code, eg:

override func viewDidAppear(_ animated: Bool) {
  navigationController?.navigationBar.barStyle = .black
}

Or in the storyboard:
Screenshot 2018-08-23 13.40.18.png

To make things ultra-confusing, if you want, for example, that your status bar has white text, view controllers not embedded in a navigation controller will need to request the .lightContent style (i.e. light colored writing), and view controllers embedded in a navigation controller will need to request the .black style (i.e. a black colored nav bar).

Don’t forget, if you have View controller-based status bar appearance set to NO, any changes you make to the navigation bar style will be ignored.

In summary

For View controller-based status bar appearance = NO:

  • General Settings of your Target / Info.plist fields
  • Set properties on the AppDelegate (deprecated, remember)

For View controller-based status bar appearance = YES:

  • Override properties in your view controller classes
  • Set style of navigation controllers / navigation bars.

So, mystery solved… sort of!  If you ask me, it’s all a bit unnecessarily complicated, but there it is, the status of the status bar!

Tagged with:
Posted in Swift

New Swift book available now, and free!

Thinking of learning more Swift, but not sure what book would be right for you?

I’ve been busy compiling a book with Manning Publications, called “Exploring Swift“, which has sample chapters from three books:

There’s some great stuff in there, including a summary of how objects work in Swift for those new to Swift, a deep dive into enums, and an exploration of solving the problem of graphic networks in Swift.

I recommend you take a look – it’s free after all, why not? Check it out here.

DkAO8_WXcAkAffd.jpg-large.jpeg

Posted in Uncategorized

What’s up with App Icons?

When you create an image set in Xcode, it’s so easy to automatically fill the wells for each scale factor. You just need to give each the three scale factor image files the correct syntax, something like:

  • image.png
  • image_2x.png
  • image_3x.png

Drag them in and Xcode automatically detects the correct well for each image, and tada!

imageSet.gif

So you’d think it would be just as easy to set up an app icon in the asset catalog. There is some automation there, but weirdly it’s a bit hit and miss.

appIcon.gif

Let’s look at what we can do about this.

Generating App Icon files

First, how to set up all of these versions of the app icon?

Easy! Apple provides a Photoshop (or Sketch or Adobe XD) template in the resources section of HIG for setting up an icon, that looks something like:

Screenshot 2018-08-01 13.20.52.png

Once you’ve set up your icon, you can specify File > Generate > Image Assets:

Screenshot 2018-08-01 13.21.05.png

And this will output all the files you’ll need to create an app icon:

Screenshot 2018-08-01 13.22.34.png

Adding icons to Asset Catalog

However, as we saw, when you drag these icons into your app icon:

Screenshot 2018-08-01 13.23.34.png

Only some wells fill, others stay blank, and some files are treated as unassigned:

fill.gif

Your first question might be:

why.gif

My guess is this is a bug in Xcode, if anyone has more info on this feel free to add a comment here. But maybe a more pertinent question is…

What to do about this?

Fix it manually

So – of course one solution is to resolve this manually, by dragging files one by one into their correct wells. Boring! We want automation!

Fix the automation

So, if you right-click on the app icon in the asset catalog, and select ‘Show in Finder’:

Screenshot 2018-08-01 21.40.43.png

Here you’ll find all of the icon files inside the project, along with a ‘Contents.json’ file:

Screenshot 2018-08-01 21.40.18.png

Here’s the magic! The Contents.json is a file used by the asset catalog to describe its assets (or folders, metadata, etc.) If you open the Contents.json file for the AppIcon you’ll find that it describes all of the app icon files, blank wells and unassigned images, something like this:

Screenshot 2018-08-01 23.13.00.png

So all the files we need are in the AppIcon folder in the Assets Catalog, we just need them to be assigned correctly in the Contents.json file. If we’ve used the Photoshop template, our files will have the same names every time, so we can simply replace the Contents.json with a standard Contents.json file that has been set up with the correct description of the files, and everything should automatically drop into the correct wells!

So, as a recap, here are the steps to follow after generating your icon files from Photoshop:

  1. Select all of the files you’ve generated (except for Icon-App-60×60@1x.png, this file is no longer included in the app icon package) and drag them as per usual into the App Icon in the Assets Catalog in Xcode.
  2. Right-click on the App Icon, and select Show in Finder. Here you’ll find the Contents.json file.
  3. Replace this Contents.json file with a corrected Contents.json file. (You can find a gist for this file here.)
  4. Tada!

CreateAppIcon.gif

There’s an app for that!

Of course there are also lots of third party solutions. Be careful though, there are plenty (even paid Mac programs) that merely create the files for you (exactly what the Photoshop template does for you) without helping you to integrate these files into Xcode.

Icon Set Creator (link here) is free and not only generates the files for you, but also generates the Contents.json file. This means you can simply import this folder into the Asset Catalog and the files will slot into their wells.

 

Tagged with: ,
Posted in Swift

What’s new Swift 4.2?

The latest update of Swift 4.2 came out last week at WWDC, and it has some pretty exciting improvements.

Some had me thinking ‘that’ll be useful’, some had me excited and some, to be honest, had me thinking ‘FINALLY!’ Here are some of my highlights:

Random

giphy.gif

One feature that I’m especially pleased about is random. Random has always been a sticking point for me in Swift – arc4random, arc4random_uniform, and drand48  have seemed out of place – more like an artifact from ancient history than a part of a ‘modern’ language, and in fact, they were! These methods directly accessed lower level C APIs.

arc4random and arc4random_uniform used and returned the little used UInt32 type (Int and UInt are much more common in Swift, which automatically uses either the 32 or 64 bit version depending on the platform your app is running on.) This means that the parameter being passed and the response always had to be converted, making a request for random extra verbose. Want a random integer between 0 and 10? Take a look at this:

let max = 10
//pre Swift 4.2
let result = Int(arc4random_uniform(UInt32(max)))

Wow. See what I mean? And if the laborious syntax isn’t a convincing enough reason – arc4random didn’t return uniform distribution of random numbers, drand48 (though it did return more useful data type Double) required an additional step of seeding, and let’s be honest – these methods had horribly ugly names!

Well – breathe a sigh of relief because Swift 4.2 has a new and exciting API with a whole range of convenience methods to make our lives easier as developers.

Remember the random integer between 0 and 10? How about this:

let max = 10
//Swift 4.2
let result = Int.random (in: 0 ..< max)

Much simpler and more readable, right? And it doesn’t have to be an integer, all numeric types have a random method now – here’s the Double version:

let max = 10
//Swift 4.2
let result = Double.random (in: 0 ..< max)

There are even collection convenience methods that select a random element.
Want to pick a suit, any suit? Too easy now:

var suits = ["Hearts","Diamonds","Clubs","Spades"]
//Swift 4.2
let suit = suits.randomElement()!

Want to shuffle the suits? Just as easy:

//Swift 4.2
suits.shuffle()

You can check out the Swift Evolution proposal for random unification here.

Bool toggle

Speaking of neat little convenience methods, here’s another!

You can now simply call the toggle method on a boolean.

No more:

//pre Swift 4.2
soundOn = !soundOn

You can now do this:

//Swift 4.2
soundOn.toggle()

You can check out the Swift Evolution proposal for adding toggle to Bool here.

New Collection higher order functions

When higher order functions come up, people often discuss the big four – map, filter, reduce and sort. In my post on higher order functions in Swift, I looked at a whole bunch of other higher order functions that collection types offer. Well, in Swift 4.2 we have more!

allSatisfy

Whereas the contains method returns a Bool based on whether at least one element in a collection satisfies a condition, the new allSatisfy method returns a Bool based on whether all elements satisfy a condition. For example:

var fruits = ["Banana","Banana","Coconut","Banana","Banana","Banana"]
//Swift 4.2
let completelyBananas = fruits.allSatisfy { $0 == "Banana" } //false

Check out the SE proposal here.

First and last

We previously had methods index(of:) and index(where:) which found the first item which satisfied a condition. We now have lastIndex(of:) and lastIndex(where:) too, which finds the last item in the collection that satisfies a condition. It made sense then to change the name of the index methods to firstIndex(of:) and firstIndex(where:).

You can find the SE proposal for first and last methods here.

Remove all

Remember the confusion you had when you first tried to remove all items from an array that satisfied a condition using a simple for loop?
You may have programmed something like:

var fruits = ["Banana","Banana","Coconut","Banana","Banana"]
//remove all bananas (naive implementation)
for (index,fruit) in fruits.enumerated() {
  if fruit == "Banana" {
    fruits.remove(at: index)
  }
}

Then everything really did go bananas when an Index out of Range error appeared in the console?

Oopsbutton.jpg

Ah for more innocent days.

Of course the index had continued to increment while the number of elements in the array steadily decreased, until finally the loop index was higher than the number of elements in the array, causing a crash. There were solutions to this problem of course – loop in reverse, for example, or use the filter method, but now we have a method built for just this task, removeAll. Take a look:

var fruits = ["Banana","Banana","Coconut","Banana","Banana"]
//remove all bananas (Swift 4.2)
fruits.removeAll { $0 == "Banana" }

Well,​ that was easier! You can find the SE proposal for remove all collection method here.

Looping through enumerations

I remember years ago having an enumeration nicely set up – I think it was something like an enum for card suits…

enum Suit {
  case hearts
  case diamonds
  case clubs
  case spades
}

…and I remember realizing I needed to loop through the cards. (Perhaps it was to find a random suit) I remember thinking – well that shouldn’t be so hard, I already have the enum set up, right?

I then realized that this isn’t a default feature of enums, and I remember thinking, “whaaa?”

Pp9rx.gif

Of course,​ there was a way around this – you could set up a static variable for example that contained an array of all the items in the enum:

//pre Swift 4.2
enum Suit {
  case hearts
  case diamonds
  case clubs
  case spades
  static var allCases:[Suit] = [.hearts, .diamonds, .clubs, .spades]
}

You could then use this allCases property to loop through the cases:

for suit in Suit.allCases {
  print(suit)
}

Well, Swift 4.2 (FINALLY!) can automatically synthesize this for you. All you need to do is adopt the CaseIterable protocol.

//Swift 4.2
enum Suit:CaseIterable {
  case hearts
  case diamonds
  case clubs
  case spades
}

Imagine – combined with the new collection convenience methods, we could now shuffle your enum case suits:

//Swift 4.2
var suitsShuffled = Suit.allCases.shuffled()

Or pick a random suit!

//Swift 4.2
var pickASuitAnySuit = Suit.allCases.randomElement()!

Wow! You can find the SE proposal for the all cases property for enums here.

Well – that’s plenty to be excited about with Swift 4.2, and I haven’t even covered everything new! If you’re interested in reading about other proposals I haven’t mentioned that made it into Swift 4.2 or perhaps are on their way for Swift 5, you can take a look over at the Swift Evolution page.

Tagged with: , , , ,
Posted in Swift

Check out my livevideo course “iOS Development with Swift in Motion”!

I’d love for you to check out my video course “iOS Development with Swift in Motion”.

 

The course is out on Manning’s livevideo platform, and if you get in early with Manning’s early access program you can get 40% off with code ytgrummitt at manning.com.

See you in the videos!

 

Posted in Swift

Block comments, key bindings and feeling foolish!

Do you ever get stuck on something, and then when you work out what you were doing wrong you feel a bit foolish?

I was just thinking – it would be much more convenient if there was a keyboard shortcut to block comment some code. I know that with the keyboard shortcut Command-/ you can automatically generate single line comments:

BlockComment3.gif

But what I was after was a keyboard shortcut to generate block comments. Strangely this capability seems to be missing from Xcode, but I happened upon an Xcode Source Editor extension called BlockComment that seemed to do the job.

So – after installing BlockComment, I went into the Key Bindings tab in Xcode preferences, double clicked on the BlockComment binding to add a keyboard shortcut, and… nothing.BlockComment1.gif

I closed Xcode, opened Xcode – did it again and… nothing. I’ve done this before, how strange! Read up on key bindings, hmm… yes I seem to be doing the right thing, what could be going wrong?

Then I watched a video and that was when I felt foolish.

Of course! You can’t just click anywhere on the line – you need to click in the key field on the right!

BlockComment2.gif

Sometimes when you work out what you were doing wrong, it all seems so obvious!

So! Things I’ve learned today

FIRST – When customizing a keyboard shortcut in Key bindings – click in the Key field!

SECONDBlockComment – works quite well, I recommend!

BlockComment4.gif

THIRD – sometimes there’s no substitute for a video tutorial!

You might think that’s a strange sentiment for a book author, but as it turns out I’m currently working on a video course to accompany the book!

Of course, everyone has a preference for how to learn. Maybe you like books coz you can read them on the train. Maybe you prefer videos as you find it easier to learn visually. Either way, you have a choice now when learning iOS development with Swift.

Combo.jpg

You can check out the book “iOS Development with Swift” here.

Or – you can check out the livevideo course “iOS Development with Swift in Motion” here. The video course is currently in the Manning early access program, and new Units will be put out regularly.

You can use both together or independently, depending on your preference!

Good luck with them, and enjoy block commenting your code with keyboard shortcuts!

Tagged with: ,
Posted in Swift

Learn iOS and Swift – interactive video course

Exciting news! For most of this year I’ve been busy working on a series of video tutorials in iOS and Swift, and this week we’re launching the Manning Early Access Program(MEAP) for the course.

There will be 13 units in total – with approximately half an hour per unit that should be hours and hours of quality content to get you up and going in iOS and Swift.

You can check out the home for the video tutorials at Manning here, or watch a preview of the course here. To promote the launch, I have a special secret discount code ( vlgrummitt ) you can use to get 50% off, but you’ll need to move fast – it’s only valid until May 3.

You can use the video tutorials exclusively if you like, or even better – as an accompaniment to my book iOS Development with Swift, out now.

So if you’ve been thinking about learning iOS or Swift – now’s the time to dive in!

DbodW3zXcAAYTuR.jpg

 

Tagged with:
Posted in Swift

Learn iOS Development with Swift now!

Exciting news – the book I have been working on for almost two years, iOS Development with Swift, is now done, published, printed and available on Amazon or in a bookstore near you.

The book is aimed at experienced programmers looking to migrate into developing in iOS with Swift. It assumes no previous knowledge of Swift nor iOS but skips over all the stuff you’ll already know from your experience in other languages.

After getting you up to speed on what’s new and exciting in Swift, the book takes you through building up an app from zero to App Store, exploring many different challenges you may encounter when working on an app, such as:

  • How do you deal with different devices or orientations?
  • What do you do if the keyboard pops up and covers the text field the user is editing?
  • What are different ways of navigating between scenes?
  • How do scenes communicate with each other?
  • How can you integrate animation and adaptive layout?
  • How can you handle background tasks?
  • What are the different ways of storing data locally and in iCloud?
  • What options are available for debugging in Xcode?

I’m very much looking forward to seeing the apps that readers produce after exploring iOS development with the support of the book! Do let me know about your app creations via Twitter, and I’ll post them on the website for the book.

If you’re interested in taking a peek at iOS Development with Swift, you can check it out now as a live book using Manning’s online reader.

Posted in Swift