Posts filed under Programming

The first beta of the was launched this past week and developers can now start making apps.

There are some limitations, but Apple released a lot more than was expected for WatchKit. There's a lot you'll be able to do within the restrictions, which are related to the embedded hardware (i.e.: Apple Watch) and it's battery life.

For now, until Native Apple Watch support is added sometime next year (fingers crossed), you'll have to work within the provided mechanisms. If something doesn't work, you'll need to let Apple know by submitting to WatchKit or Xcode.

Known Limitations of WatchKit in Xcode 6.2 Beta

  1. Updated: (Beta 2 allows Watch apps to trigger iPhone apps) You cannot press a button on Apple Watch to cause an action in your iPhone app.
  2. You cannot create or use gestures. All gestures are controlled by Apple.
  3. You cannot move objects around screen by CGPoint position (Maybe with tableview hide/show).
  4. You cannot add UI elements at run-time, everything is design time before app runs.
  5. You cannot make fluid 2D/3D games like Flappy birds (Maybe jittery gameplay with image animations + hiding/showing hackery, + borderless button).
  6. Animations are image-based (in Apple's sample they include 360 images to show a full circle progress bar = 2mb image data).
  7. Your code runs on your iPhone app in an extension (new in iOS 8), and your UI + images reside on the Apple Watch.
  8. Your app will stop if the Apple Watch and iPhone are separated beyond the range of bluetooth. Only Apple can run native apps on device.
  9. You can only use storyboard files for UI (no .xib files).
  10. You must create an iPhone app Xcode project and add Apple Watch targets to create an app.
  11. You cannot use a physical iPhone with the Apple Watch simulator. Only available in simulation on Mac.

With some of the limitations in perspective, you can design apps that provide meaningful information that compliment your iPhone app. The watch is intended to show information that can be used quickly, and it isn't designed as a gaming device because of it's limited battery and processing power.

Download and install Xcode 6.2 Beta from the Apple Developer Website

Go to  and you can download the beta versions of Xcode 6.2 and iOS 8.2 for testing out features relating to Apple Watch.

Scroll down to the bottom and read both the and the .

Download .

Getting Started with WatchKit in Xcode 6.2 Beta

In order to bring you up to speed, I've created a short that demonstrates how to create a WatchKit app using timers. There are some bugs, but this is the best place to start if you want to work with some cutting edge technology.

Please submit any bug reports to and you can help Apple improve WatchKit. Duplicate bug requests are a good thing, because it helps Apple see the more common issues.

Download the

Swift WatchKit Tutorial 1 - Get Started with WatchKit to Make apps for the Apple Watch

WatchKit Swift Tutorial 2 - Getting Started with your First WatchKit App in Xcode 6 2 Beta

WatchKit Swift Tutorial 3 - Apple Watch User Interface Explained

WatchKit Swift Tutorial 3 - Apple Watch User Interface Explained WatchKit Course: http://learn.iphonedev.tv/course/make-apps-for-apple-watch Learn how to customize the User Interface (UI) in your first Apple Watch app. There are limitations and you won't use Auto Layout like in a normal app. It's really different with a grid based layout.","source":"

WatchKit Swift Tutorial 3 - Apple Watch User Interface Explained WatchKit Course: http://learn.iphonedev.tv/course/make-apps-for-apple-watch Learn how to customize the User Interface (UI) in your first Apple Watch app. There are limitations and you won't use Auto Layout like in a normal app. It's really different with a grid based layout.

"},"hSize":null,"floatDir":null,"html":"","url":"https://www.youtube.com/watch?v=UOLi-qqvP_c","width":854,"height":480,"providerName":"YouTube","thumbnailUrl":"http://i.ytimg.com/vi/UOLi-qqvP_c/hqdefault.jpg","resolvedBy":"youtube"}" data-block-type="32" id="block-yui_3_17_2_6_1416584323551_46189">

WatchKit Swift Tutorial 4 - Connect the Apple Watch User Interface to Code

WatchKit Swift Tutorial 5 - Setup a NSTimer in Swift with Apple Watch

WatchKit Swift Tutorial 5 - Setup a NSTimer in Swift with Apple Watch WatchKit Course: http://learn.iphonedev.tv/course/make-apps-for-apple-watch The WatchKit SDK is limited. You can't run code on the Apple Watch with the current beta of WatchKit. This should change when Apple finishes the SDK for native apps.","source":"

WatchKit Swift Tutorial 5 - Setup a NSTimer in Swift with Apple Watch WatchKit Course: http://learn.iphonedev.tv/course/make-apps-for-apple-watch The WatchKit SDK is limited. You can't run code on the Apple Watch with the current beta of WatchKit. This should change when Apple finishes the SDK for native apps.

"},"hSize":null,"floatDir":null,"html":"","url":"https://www.youtube.com/watch?v=WWpd3GGzozY","width":854,"height":480,"providerName":"YouTube","thumbnailUrl":"http://i.ytimg.com/vi/WWpd3GGzozY/hqdefault.jpg","resolvedBy":"youtube"}" data-block-type="32" id="block-yui_3_17_2_6_1416584323551_48217">

WatchKit Swift Tutorial 6 - Synchronize NSTimer and WKInterfaceTimer

WatchKit Swift Tutorial 6 - Synchronize NSTimer and WKInterfaceTimer WatchKit Course: http://learn.iphonedev.tv/course/make-apps-for-apple-watch The WKInterfaceTimer runs only on the Apple Watch and doesn't have a callback to the code running in your app extension. In order to keep everything in sync you need to set a duration variable that is of type NSTimerInterval and set it for both the NSTimer and the WKInterfaceTimer.","source":"

WatchKit Swift Tutorial 6 - Synchronize NSTimer and WKInterfaceTimer WatchKit Course: http://learn.iphonedev.tv/course/make-apps-for-apple-watch The WKInterfaceTimer runs only on the Apple Watch and doesn't have a callback to the code running in your app extension. In order to keep everything in sync you need to set a duration variable that is of type NSTimerInterval and set it for both the NSTimer and the WKInterfaceTimer.

"},"hSize":null,"floatDir":null,"html":"","url":"https://www.youtube.com/watch?v=oGsFX1rEteQ","width":854,"height":480,"providerName":"YouTube","thumbnailUrl":"http://i.ytimg.com/vi/oGsFX1rEteQ/hqdefault.jpg","resolvedBy":"youtube"}" data-block-type="32" id="block-yui_3_17_2_6_1416584323551_49153">

Connect

  • Click the like button below if you enjoyed this post or any of the videos on YouTube.
  • I'll be teaching a on how to make apps for Apple Watch next year.
  • You can start my Swift iPhone app course today with 100+ videos.
Posted on November 21, 2014 and filed under iOS 8, Programming .

Return Type Error Messages are Wrong in Swift

Error messages from Xcode have a tendency to be wrong. A bad error message can send you searching in the dark in the wrong direction.

I want to share my process for searching for answers using Google and strategies that you can leverage in code to help you overcome some obstacles with Swift’s error prone error messages.

It seems that I find more wrong error message in Swift than from my experiences with Objective-C. However, that could also be attributed to my ability to fix common errors before Xcode had time to tell me what it thought was wrong in Objective-C.

I do know that I learn the most when I encounter errors and figure out how to fix them. As a beginner programmer, you will need to start identifying errors as you type them, or after Xcode points out an error message.

I’ll show an example using an error message that had me stumped, until I revisited it the next day.

Swift Compiler Error

/Users/paulsolt/Downloads/Word Magnet/Word Magnet/ViewController.swift:173:12: Cannot invoke 'init' with an argument list of type '(x: $T4, y: $T9)'

Code

func randomInt(number: Int) -> Int {
    return Int(arc4random_uniform(UInt32(number)))
}

func randomInt(number: CGFloat) -> Int {
    return Int(arc4random_uniform(UInt32(number)))
}

func randomPointInRectangle(rectangle: CGRect) {
    // Attempt 1
    return CGPoint(x: randomInt(rectangle.size.width), y: randomInt(rectangle.size.height))
} 

Ok, can you guess what’s wrong?

Google to the Rescue

I didn’t find the error message helpful, so I resorted to Googling it. Search the error message, and remove the file path and line numbers.
You can open the Issue Navigator and then right-click on an error to copy the error message to a web search bar.

Search 1

Cannot invoke 'init' with an argument list of type '(x: $T4, y: $T9)’

Nothing sticks out to me on this first search. I see MIPS assembly results from the $T4 and $T9, which look like hardware registers from assembly language. That won’t help you.

Search 2
Some of the error message is error specific, and doesn’t search well. Let’s cleanup the search text.

  1. You’ll need to remove the uniquely identifying information highlighted in bold. 
  2. Add Swift to the front of the search term. 
  3. Remove the single quotes.
Cannot invoke 'init' with an argument list of type '(x: $T2, y: $T5)’

becomes

Swift + Cannot invoke with an argument list of type (x: , y: )

The first result is good, but it’s not going to help us. It’s not the real problem that you have here. The first result is actually related to the reason I started writing this code.

http://stackoverflow.com/questions/24108827/swift-numerics-and-cgfloat-cgpoint-cgrect-etc

With two searches and you are still not understanding what is wrong. That’s normal when you first start programming. The results we found are relating to mixing Double, Int, and CGFloat types together, but that’s not the problem we’re facing.

What to do when Google Fails?

Next step when I have an issue like this is to try rewriting the line of code in a different way. You can write code that’s more verbose and that does less work on a single line of code. Separate complex statements into a separate lines of code.

Make a hypothesis and test it

Maybe there is something wrong with the randomInt() function, lets use just a number.

Workflow Tip

  1. Copy and paste the offending line of code.
  2. Comment out the first line, and alter the second line of code.

Swift Compiler Error

/Users/paulsolt/Downloads/Word Magnet/Word Magnet/ViewController.swift:174:12: Cannot invoke 'init' with an argument list of type '(x: IntegerLiteralConvertible, y: IntegerLiteralConvertible)'

Code

func randomInt(number: Int) -> Int {
    return Int(arc4random_uniform(UInt32(number)))
}

func randomInt(number: CGFloat) -> Int {
    return Int(arc4random_uniform(UInt32(number)))
}

func randomPointInRectangle(rectangle: CGRect) {
    // Attempt 2
    //    return CGPoint(x: randomInt(10), y: randomInt(10))
    return CGPoint(x: 10, y: 10)
} 

The error message is a little different, but very similar. Swift is still having an issue with the init method for the CGPoint. 

Break apart lines of code into multiple steps

What happens when you separate the CGPoint initialization from the return statement?

Swift Compiler Error

/Users/paulsolt/Downloads/Word Magnet/Word Magnet/ViewController.swift:176:12: 'CGPoint' is not convertible to '()'

Code

func randomInt(number: Int) -> Int {
    return Int(arc4random_uniform(UInt32(number)))
}

func randomInt(number: CGFloat) -> Int {
    return Int(arc4random_uniform(UInt32(number)))
}

func randomPointInRectangle(rectangle: CGRect) {
    // Attempt 3
//    return CGPoint(x: randomInt(10), y: randomInt(10))
//    return CGPoint(x: 10, y: 10)
    let point = CGPoint(x: 10, y: 10)
    return point
} 

Notice how the error message has changed?

Search 1

'CGPoint' is not convertible to ‘()’

The search results aren’t very conclusive, nothing seems to show up that’s related in the first set of results. Let’s try a different approach.

Search 2
google.com will strip a lot of special characters, let’s alter the search and try it on DuckDuckGo.com

"CGPoint is not convertible to ()” 

The search returns one related result, and it’s the solution to our problem.

https://duckduckgo.com/?q=%22CGPoint+is+not+convertible+to+%28%29%22

Swift Language Programming Guide

Reading or skimming the programming guide on Swift can also help you identify problems. If you’ve never coded before I’d recommend to type in some of the examples as you read, or you can take my online Swift courses.

If you read the , you might have a vague idea of what the error is. Upon seeing the error I remember back to something I read in the book.

Strictly speaking, the sayGoodbye function does still return a value, even though no return value is defined. Functions without a defined return type return a special value of type Void. This is simply an empty tuple, in effect a tuple with zero elements, which can be written as ().

What Xcode is trying to tell you is that it cannot convert a type CGPoint into nothing (an empty tuple). It’s referring to the return type, and if you look at the function signature for randomPointInRectangle you’ll notice that the return type is missing.

Solution

Don’t forget to include your return type in the function definition if you write return at the end of a function.

You can get some pretty strange and indirect error messages. Go back and fix the code to include the return type and the original logic.

func randomInt(number: Int) -> Int {
    return Int(arc4random_uniform(UInt32(number)))
}

func randomInt(number: CGFloat) -> Int {
    return Int(arc4random_uniform(UInt32(number)))
}

func randomPointInRectangle(rectangle: CGRect) -> CGPoint {
    return CGPoint(x: randomInt(rectangle.size.width), y: randomInt(rectangle.size.height))
} 

You have learned how to search for a solution to an error message, how to use DuckDuckGo.com when Google fails, and how to rewrite code to improve error messages in Swift.

Connect

Share the post if you found it helpful, or comment below.

  • Have you encountered a similar error message in Swift?
  • Subscribe to my mailing list and get a free Swift video course.
  • I'm teaching an online Swift iPhone app course.
Posted on November 2, 2014 and filed under Programming .

Videos Courses - Calculate Total Duration

Paul Solt Swift iPhone App Expert

I record a ton of videos on iPhone app programming, and I didn't have a good way to get the total time for a course from a set of videos.

I previously used VLC, but that gets out of hand when you have 30+ videos to manually calculate total duration.

Day 1 videos are just the beginning

Day 1 videos are just the beginning

I wrote a script in Python, since the didn't seem to work in Swift. Maybe next time it'll be Swift.

Run this code in Terminal and it'll calculate the lengths of all the .mp4 videos and output them to the console. It doesn't work with other video types, but you can grab the code and tweak it. I export all my videos with handbrake (normal settings), which gives me .mp4 video files that are small.

As of now, I have 101 videos from the first 14 days of my Swift iPhone programming course. Using this script I have a total of 12 hours 32 minutes of content.

Run the code

Open Terminal on Mac using Spotlight (Command + Spacebar) > type Terminal > Press enter

python VideoDurationCalculator.py /path/to/your/video/folder

Example:

python VideoDurationCalculator.py /Users/Shared/Course\ Videos/1\ -\ Swift\ in\ 31\ Days/Swift1\ -\ Export\ 1080

VideoDurationCalculator.py

import os
import commands
import sys

# Paul Solt - get the length of all videos within a folder (recursive)
#
# Depending on the number of files/folders, it can take time to complete
#(100 files ~2.018 seconds to run)

# Set your video folder path here
defaultPath = "/Users/Shared/Course Videos/1 - Swift in 31 Days/Swift1 - Handbrake 1080"


def main():
    path = defaultPath

    if len(sys.argv) == 2:
        path = sys.argv[1]
    else:
        print "Notice: Using default path:", defaultPath, "\n"

    #test path
    if os.path.exists(path):
        # Grab all the video (.mp4) files recursively for a folder
        filenames = []
        for root, dirs, files in os.walk(path):
            for file in files:
                if file.endswith(".mp4"):
                    filenames.append(os.path.join(root, file))

        #Calculate the total time of all videos in folder
        totalTimeInSeconds = 0
        print "Calculating video lengths..."
        for file in filenames:
            # Calculate total time
            lengthInSeconds = videoLength(file)
            totalTimeInSeconds += lengthInSeconds

        hours = int(totalTimeInSeconds / 3600)
        minutes = int((totalTimeInSeconds - (hours * 3600)) / 60)
        print "hours:", hours, "Minutes:", minutes
    else:
        print "Error: No folder found with path:", path

# Parse the plist format from mdls command on Terminal
# @return the time in seconds
# mdls -plist - filename.mp4
def videoLength(filename):

    myCommand = "mdls -plist - "
    myCommand = myCommand + "\"" + filename + "\""

    status, plistInput = commands.getstatusoutput(myCommand)

    videoLength = 0
    searchTerm = "kMDItemDurationSeconds"

    # 1. find "kMDItemDurationSeconds"
    # 2. grab text until next 

    realStart = ""
    realEnd = ""

    index = plistInput.find(searchTerm)

    # Offset by length of search term
    startIndex = index + len(searchTerm)

    # Calculate new start/end positions
    startIndex = plistInput.find(realStart, startIndex)
    endIndex = plistInput.find(realEnd, startIndex)

    #offset start by length of realStart text
    startIndex += len(realStart)

    if startIndex != -1 and endIndex != -1:
        #Split and parse as number
        numberString = plistInput[startIndex:endIndex]
        numberString = numberString.strip()
        videoLength = float(numberString)
    else:
        print
    return videoLength

# Run the main method
main()

Connect

  • Do you have a better approach?
  • Subscribe to my mailing list and get a free Swift video course.
  • I'm teaching an online Swift iPhone app course.
Posted on October 23, 2014 and filed under Tips, Programming .