Writing on Tablets Tech stuff from @yeltzland

Adding a Custom Control

I wanted a nice graphical way of showing the progress of the days counted, so I had to make a custom control.

Luckily a couple of days ago I found a great article on how to do almost exactly what I needed.

After a few tweaks from the article code to expose some hard-coded values as properties, it didn’t take long to get something up and running. I’m not going to repeat the article details here, as it’s very clear.

The easiest way of sharing code between the main app and the today widget is to put the shared code in a separate library, which can then be linked to by both targets.

The main view of the app is now much better looking…

Main view

I also wanted to add the control to the today widget, which looks a lot better now too …

Today Widget screenshot

Next steps

Improve the UI of the settings view, and overall navigation between the views

Previous posts in the series

The code for the project is also available on GitHub

Apps Swift Count The Days Left

A Today Widget in Swift

Making a widget to show on the Today notification screen is pretty straightforward, and as I’d done it before it was pretty quick to do this.

However there are a few steps that must be done correctly for this to work, so it’s probably useful for me to document them here so I remember quicker next time.

Putting shared code in an embedded library

The easiest way of sharing code between the main app and the today widget is to put the shared code in a separate library, which can then be linked to by both targets.

Adding a new target to your project via the “Editor->Add Target…” is the simplest way, and you need to select an “iOS/Framework & Library/Cocoa Touch Framework” template. I tried choosing the static library type, but that only offered me an Objective-C project type which didn’t seem correct even though the data code I’m sharing uses the Foundation code and is non-UI.

After adding the new target, it’s then easy to move the existing files - for me the data model code that’ll be shared in both the app and the widget - into the new target by making sure the files are references in the “Compile Sources” section on the “Build Phases” tab of the target properties (and obviously removing from the original target)

Finally, you’ll need to check the “Link Binary with Libraries” sections for all the targets reference the new library as appropriate, and then the Swift code has the appropriate import daysleftlibrary code to reference the library code

Setting the app group for the user settings

To allow two different targets access to the same user settings, they need to reference the same App Group where the preferences are hold.

App groups in XCode

Once that’s done, you also need to reference the group name as the suiteName parameter in the constructor of your NSDefaults object

Setting the widget title in the Today screen

By default, the title of the widget in the Today screen will take the target name, which for me was the ugly “dayslefttoday”. To be able to override this you can set the “Bundle display name” target property to the required string

Setting the Bundle display name

You can see the results of this stunning widget below:

Today Widget screenshot

Next steps

Undecided yet whether to have a play with the WatchKit, or with some animations in the main app. Stay tuned :)

Previous posts in the series

The code for the project is also available on GitHub

Apps Swift Count The Days Left

Basic UI in Swift

Now we have the data model code ready, we can start building out the UI for the app.

Basic UI

Working in storyboards, there is obviously very little difference doing this with Swift ViewController code rather than Objective-C, especially with such a simple UI.

Storyboard screenshot

As you can hopefully see from the screenshot of the storyboard, there are just 2 views in the app - one to show the number of days left, and a settings view where we can edit the values in the data model.

Later on we’ll come back to this to make the views look a bit more polished, but I just wanted get the app up and running first before tackling some more slightly interesting problems.

A few things learnt

There’s not a lot to say about the Swift code here as it’s pretty simple. However there were a few things that puzzled me a little during development that I thought I’d capture here.

I didn’t know the DatePicker control has a fixed height, which made it very confusing at first as my initial attempts as restricting the height using AutoLayout constraints just didn’t work. There are ways you can change this using frame size manipulation but I wasn’t happy with doing that in my first pass. I’ll revisit the layout of the settings page later.

Also I’d forgotten how to handle hiding the keyboard when the focus goes off a text field (or when the user presses return on the keyboard). As I’m sure you know the secret is to fire a self.view.endEditing(true) in a touchesBegan event handler, and also implement the UITextFieldDelegate and add the endEditing call to a func textFieldShouldReturn(textField: UITextField) -> Bool method as well

Next steps

Add a widget to Today notification screen, which will involve a little refactoring of the code to make common elements shareable

Previous posts in the series

The code for the project is also available on GitHub

Apps Swift Count The Days Left

Porting UserSettings code to Swift

Next stage of the app is to store the settings we previously added to both the local user settings and to iCloud for syncing across multiple devices.

Luckily I had some Objective-C code I could repurpose for most of the logic, but porting it was a useful exercise in getting used to the slightly obtuse casting syntax necessary in Swift when interacting with the frameworks.

Setting up iCloud preferences

To enable storing key-value pairs for the app in iCloud, it’s as simple as going to the Capabilities section of your project settings, and:

  1. Turn on the iCloud capabilities
  2. Make sure the “Key-value storage” checkbox is selected

Code to get and set preferences

The code - available on GitHub for viewing - is reasonably straightforward port of some common code I’ve used before.

I’ve refactored the main settings code into a BLUserSettings.swift class I should be able to reuse in other projects. The existing DaysLeftModel class now inherits from this base class, and the getters and setters have been changed to call the appropriate read/write methods in the base class.

The getters will read from the local user settings, so they’ll be available even if the device is offline. The setters will write to both the local store, and the cloud store, and the base class also handles notifications if the settings have been changed on a remote device, and writes them locally as appropriate.

Having a bunch of unit tests as always helped to test my refactoring of the model class worked fine.

Next steps

I think we’re now ready to start on the UI.

Previous posts in the series

The code for the project is also available on GitHub

Apps Swift Count The Days Left

Baby Steps with Swift

As per my previous posts, I’m developing an iOS app “in the open” using Swift as a learning experiment. It’s going to be an app that counts down the days to a future date.

Data Model design

I thought a good way of getting started would be to work on the data model code. There would be more pure Swift code to write to get up to speed on the syntax, plus I’d get the chance to write some unit tests too.

The data model design is pretty straightforward; I want to have the following properties to hold the settings data:

  • start: NSDate
  • end: NSDate
  • title: String
  • weekdaysOnly: Bool

Then there are three different access properties/methods to calculate various day lengths:

  • DaysLength: Int - the number of inclusive days between the start and the end
  • DaysGone(currentDate: NSDate) -> Int - the number of days from the start to the current date
  • DaysLeft(currentDate: NSDate) -> Int - the number of days to the end to the current date

Swift strangeness

Writing a simple class to implement this logic was pretty simple even in a new language, although a few things were a little strange at first in Swift.

Semi-colons at the end of the line are optional in Swift, and a few references I found seemed to say best practice is not to add them, although muscle memory from Objective-C and C# made this hard to do.

Also integrating into the IOS Foundation classes was a little strange in places especially the use of optional values. For example, note the ! at the end of this line

model.start = NSCalendar.autoupdatingCurrentCalendar().dateFromComponents(startComponents)!

My model.start is of type NSDate i.e. can’t be null, whereas dateFromComponents() can return a null value, so the ! forces this to actually return a value (I think!). Not the most intuitive, but thankfully the XCode editor prompted me to add the exclamation point.

The other problem I had initially was being able to reference the DaysLeftModel class from my unit test code. I couldn’t figure out anyway of importing the model code, before this very helpful blog post by Andrew Bancroft pointed out the way of configuring the build settings to automatically create a module.

Date calculations

For the date logic of calculating the difference between two dates ignoring weekends was a little tricky, but as usual the Internet was my friend and with the help of TDD and the algorithm outlined in this article by Alec Pojidaev I managed to get it working correctly.

The code

So I’m happy to be up and running in Swift, and the code is up at GitHub if you’re interested.

Next steps

I think I’ll next tackle storing these settings in a local datastore, as well as synching them with the cloud to share across devices.

Previous posts in the series

The code for the project is also available on GitHub

Apps Swift Count The Days Left