Warning: Parameter 2 to getinstance\pressmonkey\PressmonkeyAjaxHandler::title_like_posts_where() expected to be a reference, value given in /homepages/42/d156257511/htdocs/skyapp/blog/wp-includes/class-wp-hook.php on line 286Swift Posts – Sky's Swift Blog

Swift Posts

I decide it was time to upgrade an app of mine called Duality, from Swift 2 to Swift 4. It was the first native iOS app I wrote in Swift back in 2014.

There were three benefits that would make it worthwhile updating. Firstly, I needed to remove outdated interactions for social sharing. Second was to eventually give the UI more room to move on the larger screens we all have now. Back then, it was common for iPhones users to have iPhone 4 and 4S.

Third was to rewrite for the Apple APIs that have been depreciated, and this would have the added benefit of giving myself a refresh on Core data, local notifications, etc. It would also give the app longevity on the App store and be around for longer for my current users.

The conversion threw up over a 100 bugs and warnings, but I was able to fix them all in a short time considering the code was over three years old.

Better user experience

Today I just wanted to share my thinking behind one small UX feature I added for new uses that have never used the app before.

The problem

I found that when someone first opened the app, or were unfamiliar with it, they would click on the label in the centre of the screen that said “What is your best moment and worst moment of this day?”. They would then notice the buttons above this.

The solution

When they click that label, I added a subtle animation to indicate they should click on the best and worst buttons. I also thickened the stroke of the circle buttons because most screens are now 3x pixel depth and the stoke looked very thin on these screens.

I user tested it on a fresh user. Sure enough, they clicked on the label during the session. You can’t go by a sample of one, but I feel vindicated by all my past testing.

Conclusion

Animation can subtly point the user in the right direction without being annoying. It’s worth testing how users discover how your app works with no prior knowledge, and then design ways to make it easier for them to discover what they should do next.

I wanted to see if it was possible to get a constant location from the Apple Watch Series 2, from the GPS, without having the phone present.

Background Task

The first thing to check is if it was possible to run a background task to get the location every so often. The WKApplicationRefreshBackgroundTask allows you to do this, but it is budgeted by WatchOS to one task per hour so was not any use for our purpose. It is obvious why this is the case, to save battery on the watch.

Background Modes

Getting location updates from enabling CLLocationManager in the watch is not a supported background mode, so CLLocationManager is not fully featured on the watch. On an iPhone, you can run this in the background and it will provide location changes to your app in the background. The only supported mode on WatchOS 3 is Workout Processing, with the added option of sound and picture in picture related to workouts.

How does Strava get location?

Strava is a workout app, and I have checked that the watch can be used for a run and track location without the phone present. I assume that it calls a location update when it gets the callback to process workout data from HKWorkoutSession. It may call data from Health Kit and that contains location information from that workout session. I could not confirm in the Health Kit documentation that workout data contains location information.

Conclusion

It’s not possible to create an app (extension) on the watch that gets location tracking without running a workout session.

We know we need to test optionals to see if they have a value before we use them. If you use a nil value in your app, you could cause a crash. Let’s look at that.

Potential crash

Swift

1

2

3

4

// get setting1 from user defaults

letsetting1=UserDefaults.standard.string(forKey:"mySetting")

print(setting1)

// CRASH!

We want to get a String value from UserDefaults. At this point, we have no idea what the value is, or indeed if it was ever set. On first run of an app, for example, it would never have been set and have a value of nil. Usually, the best way of dealing with this is to unwrap the optional and test the value with an if statement.

Swift

1

2

3

4

5

6

// get setting1 from user defaults

ifletsetting1=UserDefaults.standard.string(forKey:"mySetting"){

// do something with setting1

print(setting1)

// "A saved string"

}

This is safe. It will only print the setting1 value if it existed. But what if we wanted to do something with setting1 even if the value didn’t exist? We could use an else statement to provide a default value.

Providing a default value for an optional

Swift

1

2

3

4

5

6

7

8

9

10

// get setting1 from user defaults

ifletsetting1=UserDefaults.standard.string(forKey:"mySetting"){

// do something with setting1

print(setting1)

// "A saved string"

}else{

// provide a default value for setting1

print("A default string")

// A default string

}

That’s a lot of code for providing a default. This is where a Nil-Coalesing Operator can help us. The Nil-Coalesing operator, ie: ??, will unwrap an optional, use it if it has a value, or use the right hand value if it finds nil.

Using ??

Swift

1

2

3

4

5

// get setting1 from user defaults

letsetting1=UserDefaults.standard.string(forKey:"mySetting")

// do something with setting1

print(setting1??"A default string")

// A default string

Great. If there is a value, it will use it, and we can provide a default value if setting1 equates to nil.

A few rules to using ??. The left hand value, ie: settings1, has to be an optional. The right hand value, must be of the same Type, in our case a String. It’s not costly to use this, because if the left hand value is found, it will not evaluate the right hand value at all.

Conclusion

The Nil-Coalesing Operator allows us to provide a default value for an optional at the time of use, and it is easy to read this short-hand method of doing so.

Xcode’s source editor is a quick way to navigate the properties and methods of a source file. At the top of each source file, is a dropdown that allows you to jump quickly to where you want to go in any source file. Selecting collectionView in this example will show a menu of items you can jump to.

This is the basic menu.

Using MARK to group the menu

With MARK as a comment, you can add comments to the dropdown.

Swift

1

2

3

4

// MARK: properties

letmyList:[String]=[]

letmaxLevel=0

The result is a menu item in the place that you wrote the MARK comment. You can jump to these like any other method or property.

You can go one better and break sections up into groups just be adding a dash like so.

Swift

1

2

3

4

// MARK: - properties

letmyList:[String]=[]

letmaxLevel=0

The result is a divider separating the MARK sections in the menu. It’s a great way to group code together.

TODO and FIXME

Other comments that show up in this menu are FIXME and TODO. You can leave yourself reminders for bugs you find and tasks that you need to do later. A number of languages recognise these comments.

Swift

1

2

3

letmyList:[String]=[]// TODO: variable name to vague

letmaxLevel=0// FIXME: make this an optional - can be nil

Let’s see them in action in the source menu.

Conclusion

Organising your source menu can logically group together your code, help you to quickly find tasks, and bug comments, and give you quick access to where in the file you need to go. It is especially handy when the source file gets too large.

Deciding on a good function name will help you later to remember what the function does and what it is expecting from you for the parameters you pass. I’m a big fan of long function names. If it takes the guessing out of what the function does, then I’m all for it. I can’t see any real advantage to having it short.

What is not used often enough is more explicit parameter names to go along with the great function name we created.

Consider you have a function that returns the day of the week by passing it an index which is an Int.

Swift

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

letindex=3

// returns short day of the week by index

funcdayOfTheWeekForIndex(index:Int)->String{

letdays=["Mon","Tue","Wed","Thu","Fri","Sat","Sun"]

returndays[index]

}

letday=dayOfTheWeekForIndex(index:index)

print(day)

// Thu

Well, it is obvious enough from the function name what this does, but index is used three times.

Using _ to avoid using a parameter label

What we could do is lose the parameter label by using _ before the index parameter which will be used by the function itself.

Swift

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

letindex=3

// returns short day of the week by index

funcdayOfTheWeekFor(_index:Int)->String{

letdays=["Mon","Tue","Wed","Thu","Fri","Sat","Sun"]

returndays[index]

}

letday=dayOfTheWeekFor(index)

print(day)

// Thu

When calling the function, we do not need to use a label at all.

This is better, but we can shorten the function name by allowing the parameter label to explain what we need for this function, and the variable index was named in a way that does the rest.

Allowing the function parameter to act as a label only

Swift

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

letindex=3

// returns short day of the week by index

funcdayOfTheWeek(forindex:Int)->String{

letdays=["Mon","Tue","Wed","Thu","Fri","Sat","Sun"]

returndays[index]

}

letday=dayOfTheWeek(for:index)

print(day)

// Thu

The for label allows us to have a placeholder that isn’t used in the function itself. We can take advantage of this to achieve a shorter function name. Xcode will display that it requires an Int on auto completion of the function, so there is never a need to put types in the label. You wouldn’t use forInt for example. This is how Xcode displays it.

Conclusion

The parameter label can help us shorten the function name, and provide a clearer idea what the parameter should be, and all this can be done without changing code in the function itself.

You can use Guard to early exit a loop or function to prevent the rest of the code executing when it doesn’t have what it needs to run. This kind of safety is what makes apps stable when things go unexpectedly wrong.

Consider you have a function that builds a filename from data in your app.

Swift

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

// adds a suffix to a filename

funcaddSuffix(name:String,suffix:String)->String{

letstr=name+"."+suffix

returnstr

}

letfileName=addSuffix(name:"myImage",suffix:"jpg")

// myImage.jpg

// oh dear

letotherFileName=addSuffix(name:"",suffix:"")

// .

We can not afford empty strings, which may cause crashes elsewhere in the app. For the sake of safety, it would be a good idea to make the function return an optional, and check for empty strings.

Swift

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

// adds a suffix to a filename and returns an optional

funcaddSuffix(name:String,suffix:String)->String?{

varstr:String?=nil

// check strings are not empty

ifname.characters.count>0{

ifsuffix.characters.count>0{

str=name+"."+suffix

}

}

returnstr

}

ifletfileName=addSuffix(name:"myImage",suffix:"jpg"){

// do something with fileName

}

This works, but if the function was complex, and lots of code generated the filename, then we need it to exit early if the function did not have what we needed to generate a safe filename.

Using guard in a function

Let’s use guard to exit early.

Swift

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

// adds a suffix to a filename and returns an optional

funcaddSuffix(name:String,suffix:String)->String?{

// return nil if we have any empty strings

guard name.characters.count>0&&suffix.characters.count>0else{

returnnil

}

// lots of code to generate filename

letfileName=name+"."+suffix// short version

returnfileName

}

ifletfileName=addSuffix(name:"myImage",suffix:"jpg"){

// do something with fileName

}

ifletotherFileName=addSuffix(name:"thisImage",suffix:""){

// will not fire

}

The guard statement will return nil if the test given to it returns false. Below this, we know that name and suffix are not empty, so we can use them with confidence and return the result. This allows the code to be shorter, and more readable after the guard statement.

You can do the same thing with a loop. Lets look at an example of a guard statement speeding up a loop by exiting early using continue.

Using guard in a loop

In this example, we have an array of optional Strings, but one of them is nil.

Swift

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

letarray=["1","2",nil,"4","5"]

foriteminarray{

// complete the block early if optional is nil

guard item!=nilelse{

continue

}

// lots of code here

// can safely unwrap the optional because we know it is not nil

print("We found \(item!)")

}

// We found 1

// We found 2

// We found 4

// We found 5

With Guard, you can use return, break or continue to exit out of code early.

Conclusion

Guard can save CPU cycles in a loop or lots of testing during a function, and has the added benefit of making the code more readable, and much safer.