Tag Archives: updates

This Old App: 2013 Code, Meet Xcode 8

A few months ago my app Interval RunCalc was removed from the App Store for being too old and not updated. In this series of articles I’ll document what I did on rebuilding and improving the app. In our first article I analyzed the changes necessary. In the second, I built the model in a Swift playground. Now it is time to place that model into the old app, and make a temporary view and controller to test it.

Open the App in Xcode

I made a copy of the original app development files, then opened them in Xcode. The issue navigator started complaining right away:

Clicking on the issue, I find several updates Xcode wanted to make.

I select Perform Changes resolving the issues. I find in the target settings for the project, there’s more issues: provisioning profiles for debug and release.

>

Above the issue, I’ll find a checkbox Automatically Manage Signing. I check that and enable the automatic signing.

I find provisioning one of the most irritating parts of working with Xcode. Anything to get me away from it is a good thing.

Of course that’s not the end of the issues. I get another error message.

If I manage singing automatically, I have to pick the team. I only have me so I pick myself from the drop down. The target is set up, and Xcode is happy again.

Configuring the New Version

This is a major version update for the app. I want to change the version number to version 2.0. Originally I wanted the app to be called runner’s calc, but that name was taken. I settled on the mouthful Interval RunCalc. That’s too long for an icon, I want to change the Display Name to a shorter name, Run Calc to show better on an icon.

The next change I’ll make is the deployment info. Currently, the deployment is iOS 8.0 and only on iPhone in portrait.

Which iOS version to set to is a good question. In most cases, you want to deploy a version or two back for compatibility. Here’s where getting user data comes in handy. I’ll use iTunes Connect’s analytics, and look at the analytics for 2016.

Two active devices per month means there’s almost no one but me using this. Usage data strongly hints me that the biggest user is me. The large peaks occur at races I either ran or was a spectator (marathons are my 2018 goal). While a second user might be at the same races, I find it unlikely.

I’m looking at a sample that’s less than a third of total apps out there. Still, upping the version to 10.3 is not tragic since it looks like nobody but me uses this. I’ll bump it up all the way for the revision. I’m also going to make this a Universal app instead of a iPhone app. My new settings look like this:

Later, I’ll set the iPad and iPhone interface to the same initial storyboard.

The Old Structure

Opening the project navigator, You can see how I put together this app:

You’ll see the root files are the RunnersCalc files. The top level contains the initial view controller and the help controller. There was a help controller, though no one knows how to get to it — I unfortunately hid it too well. If you got to it, it was just written instructions, and very badly written. It’s another thing to go on the list of changes.

The folders under this root level has one folder for the model, and three folders for the view controllers: Intervals, Input controls and Splits.

For those from a completely Swift background, those .h and .m files are Objective-C files. The .h files contain a header which indicates what properties and methods are sharable to the rest of the app. Your code is in the .m files.

Opening up the Model folder and clicking the PCPace.h file, I find the declarations for the model, the properties of the model were:

//properties of the object

@property NSTimeInterval pace; // seconds per mile

@property float speed; // miles per hour

@property float distance; //miles

@property NSTimeInterval time; //seconds of the run or split

@property NSTimeInterval splitPace; //seconds per mile or km

@property int splitCount; //total number of splits

@property int splitNumber; //current split -- necessary?

@property int fullSplitCount; //number of splits for the full mile/kilometer

@property NSTimeInterval elapsedTime; //elapsed time in a split

@property float totalDistance; //totalDistance to this point

enum PCVariable {

  kcPCSpeed,kcPCDistance,kcPCPace,kcPCTime

};

@property enum PCVariable finding;


Add the Playground Code to the App

I’m not too worried about any of this code, since I’m about to replace it all. I open up the RunStats playground so I can copy my code. I have the code stored in four files:

In the App project, I’ll make four new files in the model folder. I’ll select the Model Folder first to keep the group correct as I add files. I’ll hit Command-N to make a new file. There’s several ways I can make these files, since I’m cutting and pasting everything into the file. I’ll select Swift File for the template, though I could have just as easily picked a Cocoa Touch Class subclassing NSObject.

I’ll be asked to save with a file name. I’ll call this one RunStats.

On the bottom, I’ll make sure the target is correct and the Group is Model

We click Create, and get a new Message:

I usually create the bridging header. As the message says the bridging header opens up the classes, methods and properties in the Objective-C code to the the newer Swift code if you want to use it. In this application I won’t use it. However, it is not a lot of overhead. I’m planning to scrap all the Objective-C, but I never know in an intermediate step if I’ll need it, so I’ll create it anyway.

I’ll repeat this three more times for the classes DistanceStat, PaceStat and TimeStat. I have two classes in the RunStats playground page. I’ll add one more for RunStatsIntervals, so every class has its own file.

I’ll organize this a little better. I’ll select my Objective-C files PCPace.h, PCPace.m, and the bridging header. I’ll right click and make New Group From Selection, naming the group Objective-C. I’ll do the same for the Swift code, selecting it all and making a Swift group for it.

I’ll select RunStats, and see this:

//

// RunStats.swift

// RunnersCalc

//

// Created by Steven Lipton on 4/6/17.

// Copyright © 2017 Steven Lipton. All rights reserved.

//



import Foundation


I’ll delete the import foundation, and then copy and paste my RunStats class from the playground to the App, leaving the intervals class and the test data in the playground. I’ll make sure I copy the import UIKit when I do. It will of course have lots of errors for the moment. We have the three classes it refers to yet to add. I’ll do the same copy and paste to the other four files, adding the classes and import UIKit in each case.

Once I’m done with this there are seven issues to solve. When transferring a playground, you’ll probably get these errors.

If you click on the first error, it will show you this in the editor:

The time.seconds() and the distance.meters() lines Xcode wants to assign to something. I used them to get a quicklook for debugging the playground. All the errors are like this. The simple solution is delete that code. The fatal error is the same thing. it’s on the line

 self.pace

It was to get a quicklook for the object in the playground. I deleted it to clear the error.

A New View and Controller

The new model is in the app, and I’d like to test it. Right now, this code is ignored by the app. What I’ll do is set up a new storyboard to check the model. In the Storyboards group, I have a blank iPad storyboard and the Main_iPhone.storyboard file, which has the current storyboard for the app:

This is a big mess. This is one of those times when doing an update project like this you just shake your head and wonder what you were thinking back then. With a little investigation, you’ll find some of those answers. I iterated this model with a inadequate model to start, and I needed a lot of UI to cover up my mistakes. The major reason this app never had an iPad version was I’d have to replicate this storyboard on an iPad.

The new app had a completly new Storyboard. I’m using auto layout to need one storyboard for all devices. I Press Command-N, selecting a Storyboard object and name it Main, making sure my Group is Storyboards.

The storyboard I get is completely blank. I’ll drag a view controller onto the storyboard

I’ll change the attribute to give this a name and set this view controller to Is Initial view controller.

I’ll need a ViewController file for this scene. I’ll press Command-N again, click a Cocoa Touch Class for the template and make the Class RootViewController, subclassing UIViewController and Swift as the language.

When I save the file I’ll save it to the RunnersCalc root folder, where the root and help view controllers are. Going back to the main storyboard, I’ll set the Custom Class to RootViewController. Now I’m ready to add some controls.

This first layout is only for testing purposes. No auto layout just yet, just drag and drop. I’ll add a label for a result and a button to calculate the result. I’ll use text fields for input, so I’ll need room for the keyboard.  I’ll set the button at the center of the iPhone screen, giving the keyboard I hope plenty of room, and the result at the top. I’ll make the label read Result and the button Calculate

I Drop two text fields between the label and the button, which I’ll call variable 1 and 2. That will be for decimal values. For time values I’ll add three textfields under those two text fields. The layout looks like this, using placeholder text for titles.

Next, I’ll wire up my view controller. I’ll open the assistant editor. All but the button are outlets, So I’ll do those first, control dragging into the view controller.

@IBOutlet weak var result: UILabel!

  @IBOutlet weak var variable1: UITextField!

  @IBOutlet weak var variable2: UITextField!

  @IBOutlet weak var hours: UITextField!

  @IBOutlet weak var minutes: UITextField!

  @IBOutlet weak var seconds: UITextField!

I’m keeping this very generic for a reason. This is a test bed. I’ll use these same fields to check different parts of the model. I’ll calculate the values in code in the calculate button, which I now wire up as an action.

@IBAction func calculate(_ sender: UIButton) { 

  }

There’s a function I’ll need in the view controller. It will take a TextField and convert the text in it to a Double. I can close up the storyboard and assistant editor, and then add the function to RootViewController

  func double(textField:UITextField!)->Double{

    guard let textField = textField 

       else {return 0.0} //uwrap textfield

    guard let value = Double(textField.text!) 

       else {return 0.0} //find double

    return value

  }

This will give me a value of 0 for anything that isn’t a true Double, and return a Double if it is. There’s three optionals, and I deal with all the unwrapping here giving me a value or a zero. This is not something I’ll need in the finished code. The input system (which we cover next time) will restrict the user to only valid values.

With the structure of the test bed done, I’ll add the model to the code.

 let runStats = RunStats()

I’ll test the function the IBAction calculate. I’ll start with a simple test to make sure everything works, converting kilometers to miles.

@IBAction func calculate(_ sender: UIButton) {

    let distance = double(textField: variable1)

    runStats.distance.distance(kilometers: distance)

    let resultText = String(format: "%02.2d", runStats.distance.miles())

    result.text = resultText

  }


I use the double function to turn the variable1 text field into a double, then add it to the model with a kilometer measure. I change the distance to miles in a string, placing the result in result.

I’m almost ready to run this code, but there’s one more thing I need to do: Change the initial storyboard. In the General tab of the Target Properties, you’ll find this:

When run, the app goes to the old Main_iPHone storyboard, not the new Main. I also restricted the layout to portrait in the old version, and I’ll use all orientations for the new version. I set both the iPad and iPhone to the same storyboard Main:

Setting my simulator to an iPhone 7 I run the app. Two things happen. I get 44 warnings, but the app runs. I try putting in a value. I find I didn’t leave enough room for the keyboard

I’ll stop the app and move the calculate button up. I try running again. I’ll type in 5 when the calculator appears, and get rewarded with a value of…Zero instead of 3.11.

I first check to see if the model is working right with a few print statements

@IBAction func calculate(_ sender: UIButton) {

    let distance = double(textField: variable1)

    print("distance in km \(distance)")

    runStats.distance.distance(kilometers: distance)

    print("distance in km \(runStats.distance.kilometers())")

    print("distance in km \(runStats.distance.miles())")

    let resultText = String(format: "%02.2d", runStats.distance.miles())

    result.text = resultText

  }

When run, I get output on the console:

distance in km 5.0

distance in km 5.0

distance in km 3.10685596118667

The model is working fine. My bug is a silly one of setting the format wrong in the string. I change the format to this:

let resultText = String(format: "%6.2f", runStats.distance.miles())

When I run again, the test works.

I go back to the storyboard. That alphanumeric keyboard is annoying. For all the TextFields, I set the keyboard type to decimal pad.

I’m ready to try another test. Let’s take distance in miles and a speed in miles per hour and calculate time. I’ll convert distance and speed to Doubles, then set them to the runstats model. I’ll try this code.

@IBAction func calculate(_ sender: UIButton) {

    let distance = double(textField: variable1)

    let speed = double(textField: variable2)

    runStats.distance.distance(miles: distance)

    let pace = PaceStat(milesPerHour: speed)

    runStats.time(changedBy: pace)

    result.text = runStats.time.hoursMinutesSeconds()

  }  

I try a simple case where I run five miles at five miles an hour, And yes, I get the expected one hour.

I try a function with a time variable using the three textfields on the bottom. I’ll compute the pace in minutes per mile for a given distance.

@IBAction func calculate(_ sender: UIButton) {

    runStats.distance = DistanceStat(miles: double(textField: variable1))

    let seconds = Int(double(textField: self.seconds))

    let minutes = Int(double(textField: self.minutes))

    let hours = Int(double(textField: self.hours))

    let time = TimeStat(hours: hours, minutes: minutes, seconds: seconds)

    runStats.pace(changedBy: time)

    result.text = runStats.pace.minutesSecondsPerMile()

  }

I build and run this. A simple test is a one hour run of five miles, which should give us a twelve minute mile.

And my target time for my first marathon of five hours 45 minutes ( yeah, I’m a bit slow)

As expected, I get the 13:10 pace. I’d do a lot of tests like this to make sure the components work with the model.

A Model Change

During the testing, I get the feel for using the code in the model. There’s one thing I don’t like. Consider these two statements

runStats.distance.distance(miles: 5.0)

print(runStats.distance.miles())

I use different identifiers for the setter and getter. I like this better:

runStats.distance.miles(5.0)

print(runStats.distance.miles())

It is easer to read and shorter to type. It is not a huge change in the model code, and it works better. I can change the setters to this:

//set distance from miles

  public func meters(_ meters:Double){

    distanceStat = meters

  }

  public func miles(_ miles:Double){

    distanceStat = miles * 1609.344

  }

  public func kilometers(_ kilometers:Double){

    distanceStat = kilometers * 1000.0

  }


I change the resulting code using these functions in the rest of the model. I’ll do the same for the other stat types. The current code only requires changes to the stat types DistanceStat, PaceStat and TimeStat. Pace and time add one wrinkle in two and three parameter setters. The first parameter becomes the name of the setter, and the rest are parameters like this:

public func hours(_ hours:Int,minutes:Int,seconds:Int) {

    timeStat = Double(seconds + minutes * 60 + hours * 3600)

  }

I didn’t do it intially, but some uses of these functions in initializers will need to specify self to work properly.

public init(minutes:Int,seconds:Int){

    self.hours(0, minutes: minutes, seconds: seconds)

  }

Running the code as written I get the same results, and no problems.

The 44 Warnings 

There’s one last thing to address: those 44 warnings. Closing the folders they are in, I find they fall into the following categories:

Those warnings are why Apple wants me to change this code, and threw me out of the app store to do it. This is all old stuff that needs updating. Sometimes living in the Swift world, I forget the Objective-C is improving over time too. The deprecations for example are all the same issue: there’s no more UIActionSheets in iOS.  Many of the others are number conversions which changed in newer versions of iOS in Objective-C

I have choices here: I can fix this code and remove the errors, I can ignore the errors for now, or I can delete the code now. While the errors are annoying, they are not affecting the code. I go for the last one. I will delete all of the Objective-C code before shipping, replacing it with the new Swift code. It doesn’t need to be there, but I use it as documentation for the old version until I don’t need it anymore.

So I got the new model into the old code. I started replacing components, and got the old code to actually function in the latest Xcode. My next steps are to get the views and controllers working properly. I”ll start that process not at the root, but by replacing those text views with UIPickers in the next installment.

I’m a LinkedIn Learning author, with five courses up in the LinkedInLearning library.  My latest is a trilogy for iOS notifications: Learning iOS NotificationsiOS App Development: Notifications, and watchOS App Development: Notifications If you a re interested in Notifications, I’d Check them out. 

This Old App Episode 1: The Evaluation Stage

Before anyone thought that home improvement could be sexy, WGBH Boston started a series on house restoration. This Old House is  still going strong after 36 seasons. If you’ve never watched, each season a house in bad shape undergoes restoration. The cast goes through the paces of find what’s wrong, finding solutions and doing the work to make a new, beautiful home.

Recently, I headed over to my often neglected iTunes connect account, logged in and was met with the bright and friendly message:

 The following apps have unresolved issues and have been removed from the App Store:

Interval RunCalc

Going into the app, I found the message I expected to see:

Dear Developer,

On September 1, 2016, we announced that we’re implementing an ongoing process of evaluating and removing apps that no longer function as intended, don’t follow current review guidelines, or are outdated.

We noticed that your app has not been updated in a significant amount of time.

Next Steps

To keep your app on the App Store, submit an updated version for review and make sure it follows the latest App Review Guidelines. If you are unable to submit an update within 30 days, your app will be removed from the App Store until you submit an update and it is approved.

If Your App is Removed

Your app will remain fully functional for current users. They will experience no interruption to services, will still be able to buy in-app purchases, and can re-download the app while restoring from an iCloud or iTunes backup. However, we recommend that you update your app as soon as possible to reinstate it on the App Store and ensure that it remains functional and engaging for new and existing customers.

You can continue to use your current app name, as your app has not been deleted from your account.

Yep my app was one of the one removed in the great culling Apple threatened back in the fall of 2016. IntervalRunCalc was one of the apps that hit the chopping block. I wasn’t upset since the app had  only 13 sales in 2016. This isn’t big money, so really its no big deal if it lives or dies. If it had been more popular,  I would have been doing the revisions necessary to keep the app

I’ve just finished writing a piece for LinkedIn on Peanut butter and programming, which was a metaphor on what developers go through on a regular basis. I thought to follow up on that metaphor, I ‘d go through the process with a real app. I could go through the whole development process of Interval RunCalc, rebuilding the app using Swift instead Objective-C. Unlike my usual API of the week column, I thought of a This Old House type series on rebuilding an old app.   So for the next couple of weeks, I’ll be doing just that. We’ll explore the old application, then build models, new interfaces and putting it all together in controllers. We’ll go through the debugging process for the new app, and my adventure in getting the new app processed for Apple.  Along the way I’ll go through some good habits, find some old bad habits, and let you see my decisions as I rebuild the app.

The Original Interval RunCalc

Before we begin, you need to know the story of the app. Knowing the story of your app sets a lot of your design decisions.  You’ll need to know a little bit about running and one particular running coach, Jeff Galloway.  Running is a very popular form of physical exercise around the world. There is a lot of concern among non-runners and beginner runners about injury. Jeff Galloway, a 1972 Olympics  10,000 meter competitor for the U.S. and later running coach formulated a simple solution to the injury problem: don’t run so much by walking a little. His Run/Walk/Run method adds walk breaks or intervals during a run. You could for example run one minute, recover for thirty seconds, and the run another minute. You can workout on more complex patterns.  My current training runs for the upcoming race season is run four sets of  30 seconds run, 30 seconds walk, then pause for an full minute walk break, then repeat those for the length of the run.

For beginner runners, this has made entry into running easier, and has probably been one of the contributing factors to the popularity of race running. For older runners, the impact on bones is far less. There is a lot of evidence for cardio benefits of alternating between high intensity to low intensity activities repeatedly. Some faster distance runners are beginning to experiment with 30-second and less walk breaks once a mile to combat fatigue and run faster late in the race.

If you want to plan out a run walk run interval pattern to achieve a specific time or pace, there was no calculator to do it.  As a runner, I originally did it on spreadsheets, but the measurements systems necessary for pace, time and speed made such efforts clumsy. I wanted a tool, and figured others did too that did the calculations for me quickly. Input some numbers for intervals and walk breaks. Get back a pace, time and distance traveled. That’s why I wrote version 1.0 of Interval RunCalc.

The home screen contained basic information on pace, distance, time and speed. By changing one of these four variables you could see how it affected the other four.

This interface was very confusing, since you need to press the correct button and enter the figures correctly. Even for me, the developer, this was confusing. I fell victim to a very easy trap many developers fall into: Not testing the UI and believing what works is good enough.

Unless you know better, there were two more views in the app.  They were hidden in a button at the top.

 

Tap the button and you got a menu:

The Splits Calculator gave the splits at mile intervals and calculated your time if you decided to run some of those miles slower or faster.

  The interval calculator was the reason for the app. The user would input a series of intervals for the Pace,Speed,distance,and time.The calculator would give average pace, distance, and elapsed time back. The idea was to plan interval training runs using the app. Again, these interfaces worked, but was not easy to use.  I also added a few buttons at the bottom of the app that were confusing for adding and duplicating the intervals.

The last series of scenes I made were input scenes. Users would enter in values for HH:MM:SS time or MM:SS pace. A decimal keypad would enter  distance and speed. These all presented huge data validation problems, particularly the time.

    

Enter the Watch

A few months after the launch of Interval runcalc the Apple Watch came out. As fitness watch, it worked well with Apple’s products but not other companies. As of this writing, many still have annoying latency problems. You might  look at your watch for several seconds before getting an accurate number for your pace, time and distance. When I moved to an Apple watch from my Nike+  GPS watch, this drove me nuts. There is one exception to this latency problem: Apple’s native fitness app, which also has the active heart rate monitor data. Apple’s watch app however has no interval notifications. You can find those on a few of the big run-tracking apps, but not apple’s fitness activity app.

One solution did present itself. One of the 3rd party apps I used did intervals and sent a local notification to the phone when it was time to change intervals. When the phone went to sleep two minutes into a run, the notifications went to the watch — I had my notification by a tap on my wrist. I’d run both the app and the the apple fitness app at the same time.

If we’re going to update runcalc, there’s this one active thing it could do: send local notifications at the run/walk/run intervals. That way you can run this app in the background while using an apple watch to do the run.

Other Possible Changes

The original app was for iPhone only, I’d like to get it working well on a iPad, and iPhone plus in portrait might need a different look. These are both the regular size width class, and thus the issues would be related.

There’s one more feature I might want that isn’t there. Most of the running apps that allow additions of intervals for your workout want to know how many repetitions of the interval you want. For a one minute walk and one minute run, this is relatively easy. But for a 30 second run and 16 second walk, it isn’t so easy.  Knowing how many repetitions of this interval set make up a workout would be a helpful number.

Evaluating the Changes

Given the app’s current condition, let’s summarize the problems and ideas so far:

  1. The initial scene is confusing to use
  2. The two secondary scenes, splits and intervals are hidden
  3. Intervals are not easy to read
  4. I never use the splits
  5. The intervals are hard to use
  6. Input of data is difficult
  7. Add notifications for intervals
  8. Repetition calculation
  9. iPad use(regular width size classes)

I’ll find more as I go on, but this will give me my starting point, and set me planning.

There’s a bit of advice I’d like to start with before evaluating these. When writing an app, keep to your story, the reason your app does what it does. Consistent stories make stronger products. The story of Interval RunCalc is a calculator for running interval calculations. I’m working with the number for planning purposes, not running with this. With that story firmly in my mind, I start to make decisions.

The story is about calculations for intervals, yet I set intervals on a secondary page, not the main page. It needs to be up front. Looking at the first page , I have a lot of extra whitespace. What if I added the intervals in that whitespace?

Here’s another thought: a simple continuous run is a single interval. As long as I always have one interval in the table the data on top summarizes all runs. I’m now doing two pages on a single page.

I’ll start wire framing, sketching what this might look like:

I used the simplest, fastest way to wireframe. In this stage, don’t get overwhelmed by apps and templates letting you lay out a wireframe app. Paper,  pencil, and a few highlighters works fine. As I did here I used the sketching mode of the Apple Notes app. I can clean this all up later. Work fast, or you’ll get so bogged down in distractions you’ll never get anywhere.  I’ll add two buttons on the bottom for adding an interval and clearing the calculator:

Then I get into a debate with myself: Should there be a third button, a totals button? If I select an interval on the lower half to edit it, Should I edit it in the upper Half? If so, I’ll need a button to deselect all intervals and set the upper half to totals? While compact, It again presents me with a problem: A hidden or confusing interface. It would be better to select a row in the intervals, then go to a second view to edit and enter there.

 

This would look nice and consistent on the home screen too.Each might be a button, and tapping it could change it.  I’ll also add a button for the repetitions as well.

In a few user interface changes, I cover most of the issues with 1-5.

What to Cut

My first cut is notifications. That should be a separate app.  I do have data that would make the notifications easy to add, but that does not mean I add it. Notifications are not in the story.  This happens a lot in development, often referred to as feature creep.  One keeps adding functions to an app that it becomes, slow, unwieldy and overall unusuable. One classic example is Microsoft Word, which has so many extra features outside its core story of typing out a document. I’d rather use a simpler general word processor like Pages or Google Docs instead of Word for most documents. In updating an app, unless its a feature demanded by users, avoid adding anything outside the story. If you are an independent developer, this is a lot easier than being in an organization however. You might have teammates, upper management or marketing telling you to put something in that makes no sense. The advantage of getting the entire organization to  buy into the app story is keeping everyone focused.

For the same reasons, I’m dropping the splits calculator.  Since this is an Interval Run calculator, Splits are  not in the story.

Input Views

I’ll make one more change that I have been thinking about. I didn’t like the input in V1.0.  My original notes for 1.0 tell me I hated the time it takes to use a UIPickerview as a user.  In V2.0 I’ll change all my input to picker views to restrict the user, which they are very good at doing. Unlike other picker views I’ve seen, I’ll speed up the picker with more components. Instead of 60 rows in the seconds of minutes picker component, ill have components of 0 to 5 in one and 0 to 9 in the other, so I can quick dial any number.  My time pickers would look like this:

This solves a lot of the validation problems I had with the text fields by restricting input, but speeding up the input.

The Regular Width Devices

Our final problem in our list is the regualr width devices of iPad and iPhone plus in landscape. I have a simple solution to that. I’ll have two major views, the intervals and the stats. In regular width mode, they will be next to each other instead of on top of each other

With all that decided. I have the beginnings of a new version of this app. Many of the user interface decisions were made and those influence the structure. I was a good boy and for the moment I added only one more new feature, and killed several features. I have a few more user interface decisions to make, but I’ll get to those a little later.  My next step is to get into the code, and I usually start that with the models I’ll be using in the app. In the next lesson, we’ll build those new models, and look at the old code to find some of the problems I encountered with the old model I might want to change in the new one.

The Beta Blues with the Apple Watch

In case you did not hear about the WWDC15 keynote, Apple announced that  WatchKit is now part of WatchOS2, implemented in the Xcode 7 beta. WatchOS2 has several major differences to WatchKit, most importantly native execution of apps on the watch. For the watchkit lessons I’ve been posting, I’m assuming watchkit 1, and will not yet be using the beta for WatchOS2.  I will explicitly tell you when I use WatchOS2. What you do in these lessons should not be affected by which version you use, except that those using an Xcode7 beta will see faster performance from the watch app. I’ll be posting shortly an explanation of all the differences.