Reasons Swift Should Be Your iOS Language

Intro:

Introduced with iOS 8 in June 2014 at WWDC, Apple’s developer conference, Swift is Apple’s brand new language for creating apps. Now in its second iteration, and made Open Source in December 2015, Swift is not just designed to be a simpler language, helping apps run faster and be more secure, but could also be one of the primary coding languages across other platforms in the future.

As a language, Swift enables developers to build their apps alongside interactive Playgrounds, helping them to see the results of the lines of code they write side-by-side. With computer programming skills being seen as more important than ever, part of the appeal of Swift is that it’s a comparatively easy language to learn and code in. This was by design.

As a language, work on Swift began in the summer of 2010 by an Apple programmer called Chris Lattner. Chris spent a year and a half working on the language, with the eventual collaboration of many other programmers at Apple.

This post outline the reasons why yiu should choose swift as iOS language.

1. It’s faster

Where Swift currently falls behind Objective-C is its compiler. If we look at writing a simple JSON parser in Swift and the equivalent parser in Obj-C, the following would likely be true:

• The Swift parser would contain fewer lines of code than the Obj- C parser

• The Obj-C parse would compile considerably quicker than the Swift parser

• Once compiled, the Swift parser would execute quicker than the Obj-C parser

Currently, the Swift compiler within Xcode takes longer. This isn’t linked to the number of lines of code, but the use of functional programming paradigms, which are gaining popularity in Swift. Once compiled however, Swift apps will execute faster than Objective-C, thanks to the compiler optimisations that can be made with Swift.

Swift also uses roughly half the amount of files to work with, compared to Objective-C. With Objective-C, you need a header file (.h) and an implementation file (.m), with Swift however, you just need a single .swift file. This makes it less confusing for developers that aren’t accustomed to working with header and implementation files.

2. It’s safer

As Apple says on its developer site1 : ‘Swift eliminates entire classes of unsafe code. Variables are always initialized before use, arrays and integers are checked for overflow, and memory is managed automatically. Syntax is tuned to make it easy to define your intent — for example, simple three- character keywords define a variable ( var ) or constant ( let ).’ This, in addition to removing null pointers, one of the common programming errors and routes of bugs, means apps are less likely to crash, helping to improve the user experience. “Swift uses variables to store and refer to values by an identifying name. Swift also makes extensive use of variables whose values cannot be changed. These are known as constants, and are much more powerful than constants in C. Constants are used throughout Swift to make code safer and clearer in intent when you work with values that do not need to change.” Excerpt From: 2 Apple Inc. “The Swift Programming Language (Swift 2.1).” iBooks.

3. It’s easier to learn

In a discussion with Daring Fireball host and Apple commentator, John Gruber and Craig Federighi, Apple’s senior vice president of software engineering, Craig said: ‘Swift is, we think, the primary programming language that developers should be taught programming in, actually. I mean, if you’re going to learn computer science, Swift is a fantastic learning language.’

Apple has been open with the fact that Swift was designed to be easier for people to learn, opening up coding to a wider group of skill sets. For someone with programming experience, even the complex coding within Swift is relatively easy to learn. For most people though, learning Swift is just a matter of learning its features and syntax, then practicing them. Thankfully, the official Swift documentation is easy to follow, making it easy to understand the language and how to test drive the code.

4. Playgrounds let you see the impact of your code in real-time

When developing apps using Apple’s Xcode and Swift, there’s the option of using Playgrounds, a secondary window that enables developers to test the code they’ve written and display results in real time. This is helpful for newbies learning the language and seasoned developers testing an advanced algorithm for their current project.

5. It is better at memory management

Building great apps is much harder than people may think. Creating an app is one thing, but creating one that doesn’t eat battery or use up memory, requires more expertise. Memory management issues can be harder to pin point as there won’t always be obvious bugs. Instead, memory management issues tend to manifest themselves through obscure bugs like repeat notifications or random crashes. First introduced in 2010 with Xcode 4.2, with iOS 4.0, Automatic Reference Counting (ARC) is able to track and manage an app’s memory usage. ARC has been a core part of memory management for iOS and OS X projects, since iOS 5.0. It is one of the features that has been carried over from Objective-C to Swift. In most cases, this means that memory management “just works” in Swift. There is still some work to be done here, however. Currently, the Clang static analyser, which flags up potential memory leaks, dead stores, unused variables, etc. isn’t compatible with Swift. As a tool which is built into Xcode, Clang is a useful tool for spotting potential memory issues at compile time. Whilst “just works” with Swift is often true, there are times when additional optimisations are required, which is precisely where Clang would help.

6. Now that Swift is Open Source

Being Open Source opens up Swift to the potential that it can be used across a number of different platforms and for backend infrastructure. Open Sourcing Swift means that Apple will be able to get feedback from the community to make improvements on a regular, ongoing basis. By going Open Source independent developers, development teams and academics, across the world, can all contribute to the success of the language. Various frameworks, libraries and web servers/web components can be developed by this community, all at no cost to Apple. These projects can then be used by other developers to create an unlimited number of products, making Swift more important outside of the Apple developer community.

7. It’s the top language on GitHub

A week after officially going Open Source in December 2015, Swift jumped to the top of the most popular languages on GitHub. GitHub is the go-to source for open source language development, so the fact that Swift quickly jumped to the top, and has stayed there since, is a good indication of its popularity. As Swift matures over the next few years, we can expect to see it being used by an ever increasing array of platforms. Whilst this is positive, it doesn’t mean that large companies will change their current language to Swift. Swift is the newest kid on the block, so it will take time to get adoption by larger companies outside of the development of new iOS apps.

8. It’s interoperable with Objective-C

Objective-C and C were the languages that native iOS apps were largely written in, prior to the introduction of Swift. Swift is interoperable with both, meaning developers can build on their existing apps, using Swift. This means that developers don’t have to do a full re-write. One of the most important aspects of interoperability is that it enables developers to work with Objective-C APIs when writing Swift code. This means that APIs don’t need to be rewritten to work with Swift and that apps will continue working. As it is interoperable, developers are able to slowly replace older code in apps, with Swift code, without breaking the app (though this is possible, if the coding isn’t done properly). Migration provides an opportunity to revisit an existing Objective-C app and improve its architecture, logic and performance by replacing pieces of it in Swift.

9. Swift will be server side language

Though Swift is currently just for iOS and OS X, there is a huge appetite within the developer community to use it for servers and backend development. According to Federighi4, “IBM, for instance, jumped all over Swift for building their mobile apps, and almost immediately they were coming back to us with, “We really want to use this on the server. How can we get this on the server?” Of course, it’s not just IBM, as Federighi explained to John Gruber, Apple’s iCloud team is already keen to use it for iCloud, “And our own iCloud team has been completely champing at the bit to be able to apply it in many, many of the things they do. So, I think it’s going to be one of the first break-out uses of Swift. And of course these days there are so many mobile applications that are part mobile app, part server code. And in a lot of cases, at the very least you want to share your knowledge, but very often you want to share parts of code, parts of your model layer, some of your utility libraries, and having Swift enabling you to do that is going to be huge for a lot of our community.”

Whether Swift’s use on the server takes off or not depends on what the development community does with the language. Already, developers are busy making cool projects, such as:

Swifter: a small HTTP server engine, written in Swift

SwiftCGI: a modular Microframework that encourages a functional approach to developing web apps in Swift.

Perfect : an enterprise-grade web server and web toolkit for the Swift programming language.

We can also expect to see other current Objective-C projects being converted to Swift, such as CocoaHTTPServer and HTTPKit in the near future.

Persisting Structs in Swift

Today i have been assigned another JIRA issue by my product manager. This task is simply to mock the app data or to maintain a backup of the app data like json retrieved from API. I just started to dig into the project code because i was newbie to this project and i found that our data models is written like Structs not Classes. The story started from here because that’s made me to write this post.

I’m working now on Apple TV App (YAY), i’ve never imagined that i’ll develop in tv OS, However things happens. the project i’m working on is a entertainment application like most Apple TV apps it display Video content so the home screen contain some recommendations video assets from our backend and it’s displayed as Tiles in home screen, once the user clicks on any tiles he will be redirected to asset details screen that contain details about the video clicked[he can play video, browse cast&crew, Add to Wishlist, etc]

One of the functionality that our client requested is to be able to make the app working even the backend/server is down. So we have to persist these video assets data(recommendations,…) somewhere even if the user close that app and open it again.

First of all i thought for multiple solutions for persisting these data:

1- It make sense to use NSUserDefaults to save recommendations. As NSUserdefaults is a plists which is a NSDictionaries that can includes array, strings, numbers, and even NSDictionaries. 2- I just thought to use a local json file that contain a backup json data the same data comming from backend.

Finally i decided to use both solutions for persisting these data, So the application flow was as follows:

This was the sudo code:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
call the API server to get the video assets data :
if there is a response{

// API server is responding.
- open the app normally.
- save the data locally in NSUserdefaults.
}
else {
// no response from the API server.
- check if there is a data stored locally in NSUserdefault {
    load data from NSUserdefault.
}
else {
    load data from the local json file.
}
}

The beauty of this way is that in any case we have a mock data so our app can work any time our server is down. even if this is the first time the user open the app and the server down, don’t worry the app will load the data from the local json file. Also we will have a updated mocked data because every time server is responding we save the new data in NSUserdefault so it’s updated data.

This too much information and out of scope now, sorry just thought i’ve to share it with you!

Let’s get back to the point, So we have to store an array of recommendations objects in NSUserDefaults so we can retrieve them any time.

The way we all know to make this happens was as follows:

We use NSKeyArchiver the archiving functionality to achieve that.And by the way our data persistence were not large to use Core Data or SQLite.

Archiving functionality has few parts. we have to conform to NSCoding protocol that requires to implement 2 methods encodeWithCoder and * initWithCoder* which is where we specify how to encode and decode data.

Then we implement NSCoder protocol methods in our Recommendation class as follows:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#pragma mark NSCoding methods

- (void)encodeWithCoder:(NSCoder *)coder;
{
    if (name != nil) {
        [coder encodeObject:entityId forKey:@"entityId"];
        [coder encodeObject:entityType forKey:@"entityType"];
        [coder encodeObject:entity forKey:@"entity"];
    }
}

- (instancetype)initWithCoder:(NSCoder *)coder
{
    if(self = [super init]) {
        self.entityId = [coder decodeObjectForKey:@"entityId"];
        self.entityType = [coder decodeObjectForKey:@"entityType"];
        self.entity = [coder decodeObjectForKey:@"entity"];
    }
    return self;
}

This way serialize our Recommendation object and is convert into NSData, making it easy to be persisted.

To store the encoded object as NSData we use NSKeyedArchiver archivedDataWithRootObject method as follows:

1
2
NSData *encodedWeatherData = [NSKeyedArchiver archivedDataWithRootObject:recommendations];
[[NSUserDefaults standardUserDefaults]setObject:encodedWeatherData forKey:@recommnedations_data"];

To decode the our recommendation model we have to search in NSUserdefaults for encoded object with the key “recommnedations_data” then decode and return it.

1
2
3
4
5
6
7
8
+ (NSArray *)recommendations
{
    NSData *encodedRecommendations = [[NSUserDefaults standardUserDefaults]objectForKey:@"recommnedations_data"];
    if(encodedRecommendations) {
        return (NSArray *)[NSKeyedUnarchiver unarchiveObjectWithData:encodedRecommendations];
    }
    return nil;
}

Issues with this technique:

NSCoding only works with objects inheriting from NSObject.

Currently in our Apple TV application we use Structs for the model layer so every model is basically a Struct. Actually our cannot conform to NSCoding protocol because it’s not inheriting from NSObject.

As we have a lot of models in our app and we are taking advantages of the features of Structs, It doesn’t make sense to convert/rewrite our models (Recommendation) to objects rather than structs.

Swift Approach

How we solved the problem of persisting Structs in Swift? Since we can’t archive and unarchive them like classes inherits from NSObjects.

Let’s spill out the the solution we can do:

Structs:

Recommendation model this is one of the models that we want to persist. this model is already implemented in the project as a Struct:

1
2
3
4
5
6
7
8
9
10
11
12
13
struct Recommendation{

    var entityId: NSNumber?
    var entityType: EntityTypeEnum?
    var entity: EntityProtocol?

    init(entityId:NSNumber, entityType: EntityTypeEnum, entity: EntityProtocol?){

        self.entityId   = entityId
        self.entityType = entityType
        self.entity     = entity
    }
}

Now we need a way to persist our recommendation model, we have to convert our Struct to another object that can be persisted like NSDictionary.

The idea is we can convert our Struct into NSDictionary object and then we can persist this NSDictionary into NSUserdefaults easily. and then we can extract this NSDictioanry from NSUserDefaults and brings it back into Recommendation instance.

we did that using a Protocol we used a protocol to make it more generic for all models of the project. this protocol contain two methods, one method return an NSDictionary from Recommendation instance by going through the Recommendation instance and set key-value pairs for each of the variables and returns an NSDictionary.

another method that takes NSDictioanry as parameter and return an instance of Recommendation model.

1
2
3
4
protocol PropertyListReadable {
    func propertyListRepresentation() -> NSDictionary
    init?(propertyListRepresentation:NSDictionary?)
}

Now we can extend each Struct with protocol

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
extension REMintRecommendationModel: PropertyListReadable{

    func propertyListRepresentation() -> NSDictionary {

        var representation = [String : AnyObject]()
        if let entityId = self.entityId{
            representation["entityId"] = entityId
        }
        if let type = self.entityType{
            representation["type"] = type.rawValue
        }
        if let entity = self.entity{
            representation["entity"] = entity.propertyListRepresentation()
        }
        return representation
    }

    init?(propertyListRepresentation:NSDictionary?) {

        guard let values = propertyListRepresentation
            else {return nil}
        self =  Recommendation(data: values)
    }
}

Note: You may face a problem in your implementation is that you have another struct instance inside you Struct, No worries you have to follow the same approach all your persisted Structs must conform to PropertyListReadable protocol and then you can propertyListRepresentation to get an NSDictionary for this Struct or return this Struct back from NSDictionary.

Dealing with NSUerDefaults:

1- Extracting Structs from NSUerDefaults:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
    /**
     Accept an Array of dictionaries and convert it back to Array of objects by converting each dictionary to object to be persisted in NSUserDefaults.
     it accept an optional argument of an array of any object and returning an array of our generic return value. it also are specify our generic return value must conform to the PropertyListReadable protocol.

     - parameter [AnyObject]: the array of dictionaries to be converted.
     - parameter key: The key with which to check if it has a value in NSUserDefaults.
     - returns [T]: array of objects conforming to PropertyListReadable protocol.

     */
    func extractValuesFromPropertyListArray<T:PropertyListReadable>(propertyListArray:[AnyObject]?) -> [T] {
        guard let encodedArray = propertyListArray
            else {return []}
        return encodedArray.map{$0 as? NSDictionary}.flatMap{T(propertyListRepresentation:$0)}
    }

2- Saving Structs in NSUerDefaults:

1
2
3
4
5
6
7
8
9
10
11
12
     /**
     Accept an Array of objects and convert it to Array of dictionaries by converting each object to dictionary to be persisted in NSUserDefaults.
     We’re creating an array of encoded values by taking the array parameter and mapping each one using the propertyListRepresentation function to turn it into an array of NSDictionaries.
     We then run the result through the setObject:forKey function associated with the NSUserDefaults.

     - parameter [T]: the array of objects that conform PropertyListReadable protocol to  to be saved in NSUserDefaults.
     - parameter key: The key with which to check if it has a value in NSUserDefaults.
     */
    func saveValuesToDefaults<T:PropertyListReadable>(newValues:[T], key:String) {
        let encodedValues = newValues.map{$0.propertyListRepresentation()}
        NSUserDefaults.standardUserDefaults().setObject(encodedValues, forKey:key)
    }

P.S. I’ve created a Playground that contains a working example.

Happy Coding :)

Me and Scrum

Today i heared about a tool from a friend of mine called Asana. Asana is the easiest way for teams to track their work. Asana has a a cool UI that make it easy to have a Scrum Boards.

Explanation of Scrum:

Scrum is an agile framework for managing a process. It relies on self organizing, cross functional teams to do the work. During the process the team organizes work into small well defined tasks. Tasks are organized into a “Product Backlog” which is an ordered list of tasks required to create a product. Work on the tasks is done in equal length “Sprints” which are typically one to four weeks in length.

At the start of each sprint the team takes items from the top of the Product Backlog to build a Sprint Backlog. These are the tasks they commit to completing during the sprint. Items on the Product Backlog may be very high level or very specific. However, for an item to be brought into a sprint it needs to have an estimate (provided by the team) and an acceptance criteria or definition of “done”.

Each day of the sprint the team comes together in a daily standup to communicate task progress. Each member of the team gives a short summary of what they did yesterday, what they will do today and if there is anything blocking progress on the task at hand. Teams often do this stand up in front of the Scum Board which is a white board or wall containing cards for each task in the sprint. The cards are organized into columns which show the progress of the task from ready to work on to completed (‘To Do’, ‘In Progress’, ‘Done’).

At the end of the sprint the team comes together to demo what they’ve completed during the sprint and finally to discuss the “Process” in what is called a Sprint Retrospective.

The players of the Scrum team are the Product owner, the Scrum Master and the developers/testers. The Product owner is responsible for maintaining the product backlog, providing priority and knowledge about tasks. The Scrum Master helps the team with the scrum process and works to remove any blockers. The developers/testers are the people building the product. Usually the team consists of five to nine people.

How i used Asana to create Scrum board:

I’ve started to look at Asana tool to create my first Scrum Board or Scrum project, I’ve started to create different sections into my workspace:

1- Scrum Product Backlog: Each task is a story. The task name starts with the story ID and ends with the time estimation between brackets. Use tags to show the priority (PX).

Make sure to activate the “bracket” hack, to enable automatic sum of numbers between brackets to instantly get the sum of times Asana hack

2- Scrum Sprints Backlog: Each task is a story. The task name starts with the story ID and ends with the time estimation between brackets. Use tags to show the priority (PX).

3- Scrum Sprint Burndown.

This is a screen shot from my Srum project in Asana.

And here is a video that explain how to use scrum to manage your projects using Asana. Asana

useful links:

1- Scrum Methodology. Scrum Methodology

2- Scrum project management template. templana

3- best way to use Asana with Scrum from Quora. Quora

4- Asana scrum board. Github

Symbolicating iOS Crash Reports

It’s often difficult to reproduce crashes reported from users, During your app beta testing, and even when you have apps on the App Store. Yesterday i faced an issue that my app works well in Debug mode on Xcode but it’s crash when installing it from TestFlight and trying the same scenario on it. Unfrtuanalty i was integratting InstaBug “it’s a crash reporting tool” but the trial period ended and no more crahses reported to me over email. So i have to do it manually. Luckily, iOS devices keep logs of each crash and can tell you the exact line of code that causes the problem. Let’s take a look at a crash log for my app.

From the image above only the hex symbols of the objects and the memory addresses are there, So we need to symbolicate them.

First, you need to have the .app and .dSYM for the build that generated the crash log.

These are the following steps:

Step1: Create a folder in desktop, and give it a name “CrashReport” and put three files (“MyApp.app”, “MyApp.app.dSYM”, MyApp.crash) in it.

Step2: Open finder and got to Applications, find Xcode application, right click on it and click “Show Package Contents” Then follow this path, For Xcode 6 and above the path is Applications/Xcode.app/Contents/SharedFrameworks/DTDeviceKitBase.framework/Versions/A/Resources Where you find “symbolicatecrash” file , copy this and paste it to “CrashReport” folder.

Step3: launch the terminal, run these 3 Command

cd /Users/UserName/Desktop/CrashLog and press Enter button

export DEVELOPER_DIR=“/Applications/Xcode.app/Contents/Developer” and press Enter

./symbolicatecrash -A -v MYApp_2013-07-18.crash MyApp.app.dSYM and press Enter Now its Done.. (NOTE: versions around 6.4 or later do not have the -A option – just leave it out)

Now you should see a lovely, symbolicated crash report in the terminal:

Happy Coding :)

Performance Test in Xcode

Yesterday i recieved a JIRA issue from QA that the iOS application is very slow apparently the issue was in application services(API) being very slow to perform any operation. I started to investigate in the issue and there was a use case that the user select a file then there was a 2 API that should be called to process this file to be previewed in PDF previewer, So i started to think about a way to calculate the time the process it takes starting from selecting the file untile it’s previewed. i eneded up with profiling and therfore i did some research on how to do a profiling in Xcode and i found that Xcode has an addition to unit testing it provide the ability to measure the performance of a piece of code. This allow developers to gain insight into the specific timing infotmation of the code that being tested.

Performance Testing

With performance testing you can know the average time of execution for a piece of code. Also you can define a baseline exection time. This means that if the code that’s being testd deviates from that baseline, the test fails. Xcode will repeatedly execute the code 10 times and measure the average execution time. To measure the measure the performance of a piece of code, use the “measureBlock:” API. This is one of the test cases i prepared:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
- (void)testPerformanceExample {
    // This is an example of a performance test case.
    [self measureBlock:^{
        // Put the code you want to measure the time of here.
        XCTestExpectation *completionExpectation = [self expectationWithDescription:@"Long method"];
        [self.vcToTest doConvertFile:@"" withBlock:^(NSString *result) {

            XCTAssertEqualObjects(@"success", result, @"Result was not correct!");
            [completionExpectation fulfill];

        }];

        [self waitForExpectationsWithTimeout:100.0 handler:nil];
    }];
}

But what is XCTestExpectation in this block of code, Right this is a class that enable you to test Asyncronous code. The flow to test Asynchronous code is as follows, define an expectaion, wait for the expectation to be fulfilled, and fulfill the expectation when the asyncronous code finsish executing.

Then i started to run the above test in Xcode and this was the result:

Now you can edit the baseline time of execution for the performance test.

Git Source Control in Xcode

It’s obvious that adding a Git repository to a project is totally effortless using Xcode. However, what happens if you don’t include a Git repo during a project setup, or if you want to add one at a later time? Well, the good news is that you can add a repo for your project at any time, but without using Xcode.

Befor demonstrating anything, you must download the Command line tools through Xcode, as we are going to work in terminal and we need some extra tools available. to install the command line tools, goto the Xcode > Preferences… menu on Xcode, and then select the Downloads tab. In the upper side of the window, under the Components section, click on the button with a down arrow existing at the right side of the Commnad line Tools options. Once the download is over, a checkmark will appear instead of the download button.

Now, create Xcode project for the sake of this example. make sure to deselect the Create git repository options. We don’t want Xcode to prepare a repository for us in this case. Name the project and save it in your Desktop, so you can follow along with the commands i will show.

Once everything is ready, open a Terminal window(if you have already opend any, make sure to close it first, so any changes made by installing the command line tools to be applied). For starters, navigate your self to the new project’s directory:

1
cd /users/YOUR-USERNAME/Desktop/ProjectName
1
git init

This will initialize an empty repo, and if you either go to Finder or use the ls terminal command, you’ll see that the .git sub-directory has been created. Cool. Keep going:

1
git add.

With this one, all contents of the current directory(the dot [.] symbol) will be added to the repo. Finally commit all(make the changes permanent):

1
git commit -m 'initial commit'

A list of all files commited to the local git repo will appear to the terminal window. the next screen illustrates my terminal:

watchOS 2: Animations

The new operating system for Apple Watch, watchOS 2, was introduced a couple of weeks ago at WWDC 2015. It brings a lot of improvements, mostly for developers looking to create an Apple Watch app. These are the things that I find to be most important for developers:

  • WatchKit apps are now running natively on the watch. This brings the much needed improvement in speed, resulting in a better user experience.
  • The new Watch Connectivity framework enables all sorts of communication and data sharing between the parent iOS app and the watchOS app.
  • watchOS 2 apps have access to hardware data, such as data from the motion sensor, audio recording, and they can even access heart rate data.
  • watchOS 2 also introduced animations. On watchOS 1, the only option to perform an animation was to generate a series of images and then iterate through them. watchOS 2 brings true animations to the Apple Watch. You can animate the user interface by changing layout properties inside an animation block. That’s where this tutorial comes in.

1. Why Care About Animations?

Before we get to the nuts and bolts, I’d like to spend a minute talking about the purpose of animations on Apple Watch apps.

The obvious reason is that they make the user interface more enjoyable if used appropriately. And when it comes to Apple Watch, that is a big if. Since most app interactions only last for a few seconds, you really don’t want to go overboard with animations.

The second, and I believe more important reason, is that they allow for custom navigation hierarchies inside Apple Watch apps. Let’s suppose you need to present a screen that the user can only leave by taking a specific action. Normally, Apple Watch apps always have a cancel button in the top left corner when a modal interface controller is presented. With animations and clever layout manipulation, you could create your own “present view controller” routine that shows your app’s content full-screen, dismissing it by that specific action. That is one of the things you’ll learn in this tutorial.

Basics

//Describe the animation in watchOS 1

The principle of animations on watchOS 2 is simple, you set one or more of the animatable properties inside an animation block. The following example illustrates how this works.

1
2
3
[self animateWithDuration:0.5 animations:^{
    [self.circleGroup setHorizontalAlignment:WKInterfaceObjectHorizontalAlignmentRight];
}];

This method causes the circleGroup to be aligned to the right, with an animation with a duration of 0.5 seconds. As you can see, we are calling animateWithDuration:animations: on self, which is an instance of WKInterfaceController. This is different from iOS where the animation methods are class methods on UIView.

The below list shows which properties are animatable:

.opacity

.alignment

.width and height

.background color

.color and tint color

Bear in mind that it’s still not possible on watchOS 2 to create user interface elements at runtime. But since you can hide them or set their alpha to 0 in the storyboard, this shouldn’t be that big of a problem.

That’s it. Armed with your knowledge about the WatchKit layout system, you are now ready to start working with native animations on watchOS. Let’s get started by creating a sample app so I can show you a couple of examples of how this all fits together.

How I Built Parallax Effect Inspired by Yahoo Weather

One of the first projects Yahoo’s Marissa Mayer oversaw as CEO was the Yahoo Weather app. The app was so well received that it even ended up receiving a coveted Apple Design Award in 2013.

Background:

I’m a big fan of Yahoo weather app. I intented to replicate and generalize the approach they used for anyone going to use.

Implementation:

Glassy View is a subclass of UIView. It contains two UIScrollView, background and foreground. backgroundScrollView consists of two UIImageView, backgroundImageView and blurredImageView. The alpha of the blurred one changes as the background scrolls. And the background scrolls as the foreground scrolls(at a different rate). The foregroundScrollView consists of maskLayers and the foregroundContainerView(which is whatever you want it to be).

How to use:

  1. Create an instance of GlassyScrollView init(frame: CGRect, backgroundImage:UIImage, blurredImage:UIImage, viewDistanceFromBottom:CGFloat, foregroundView:UIView) and add it as a subview to whereever you need it to be.
  2. backgroundImage is essential, pick whatever fancy image that makes all the difference.
  3. blurredBackgroundImage is not neccessary but you can provide your own custom one.
  4. viewDistanceFromBottom is how much your foregroundView is visible from the bottom (like Yahoo temperature)
  5. foregroundView this is the view that will contain all the info.

Parallax effect implementation:

To achieve the parallax horizontal effect just call func scrollHorizontalRatio(ratio:CGFloat) that control each backgroundScrollView’s contentOffset while scrolling.

The following 2 screenshots describe the behavior:

Just control the contentOffset of backgroundScrollView like this:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
func scrollViewDidScroll(scrollView: UIScrollView) {
    let ratio:CGFloat = scrollView.contentOffset.x/scrollView.frame.size.width
    page=ratio

    if ratio > -1 && ratio < 1 {

        glassScrollView1.scrollHorizontalRatio(-ratio)
    }
    if ratio > 0 && ratio < 2 {

        glassScrollView2.scrollHorizontalRatio(-ratio + 1)
    }
    if ratio > 1 && ratio < 3 {

        glassScrollView3.scrollHorizontalRatio(-ratio + 2)
    }
}
1
2
3
4
func scrollHorizontalRatio(ratio:CGFloat){
    // when the view scroll horizontally, this works the parallax magic
    backgroundScrollView.contentOffset = CGPointMake(maxBackgroundMovementHorizontal+ratio*maxBackgroundMovementHorizontal,     backgroundScrollView.contentOffset.y)
}

Scrolling all foregroundScrollViews Vertically to the same point implementation:

To simulate the same behavior achieved by Yahoo’s Weather app that scroll all foregroundScrollViews Vertically to the same point, just control the contentOffset of foregroundScrollView and change offsetY accordingly.

So let’s assume that you scrolle one of the foregroundScrollViews vertically so then all foregroundScrollViews(others foregroundScrollViews 2 foregroundScrollViews in our case) should be scrolled vertically to the same point(offsetY) accordingly.

The following screenshot describe the behavior:

Start by calling scrollVerticallyToOffset(offsetY:CGFloat) for each glassScrollView in scrollViewWillBeginDragging:

1
2
3
4
5
6
7
8
9
func scrollViewWillBeginDragging(scrollView: UIScrollView) {

    let glass:GlassyScrollView = currentGlass()

    //this is just a demonstration without optimization
    glassScrollView1.scrollVerticallyToOffset(glass.foregroundScrollView.contentOffset.y)
    glassScrollView2.scrollVerticallyToOffset(glass.foregroundScrollView.contentOffset.y)
    glassScrollView3.scrollVerticallyToOffset(glass.foregroundScrollView.contentOffset.y)
}

Then get the current Glassy scrollview:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
func currentGlassyScrollView() ->GlassyScrollView{

    var glass:GlassyScrollView=glassScrollView1

    switch page{
    case 0:
        glass = glassScrollView1
    case 1:
        glass = glassScrollView2
    case 2:
        glass = glassScrollView3
    default:
        break

    }
    return glass
}

And then call scrollVerticallyToOffset(offsetY:CGFloat) to change the contentOffset of foregroundScrollView accordingly:

1
2
3
4
func scrollVerticallyToOffset(offsetY:CGFloat){

    foregroundScrollView.contentOffset=CGPointMake(foregroundScrollView.contentOffset.x, offsetY)
}

Check out Glassy control on GitHub.