Info

Programmer by day, artist by night

Usually it doesn’t make much sense to repeat code from a lecture demo, but for the Dropit project I think it’s worth to post an article based on a slight variation using the new features of UIKit Dynamics available in iOS 9.

This is perhaps a good time to mention that all the CS193P assignment solutions so far created has been based on Swift 2.1 and iOS 9, whereas the Stanford U. lectures and demos are based on Swift 1.2 and iOS 8.

The motivation to create the variation was a result of attempting to implement assignment 5. Particularly the ball which is a UIView and ideally should be round, even though UIViews are obviously rectangles. The good news is that iOS 9 provides a collisionBoundsType property which can be easily overridden in UIView:

class SphereView: UIView {
    // iOS 9 specific
    override var collisionBoundsType: UIDynamicItemCollisionBoundsType {
        return .Ellipse
    }
}

This sets the bounds of the view to be an ellipse and allows the right boundary collisions
as you might expect from a ball or sphere.

dropit-spaces-between-spheres dropit-no-spaces-between-spheres

The UIFieldBehavior new in iOS 9, also seems very interesting with properties like: dragField, springField, electricField, magneticField, noiseFieldWithSmoothness and more, which opens the door to new possibilities of animation in your apps. The Dropit variation also adds the noiseFieldWithSmoothness behavior for some cool
visual effects.

dropit-spheres-in-noise-field

With debugEnabled for UIDynamicAnimator (by adding a Swift bridging header *), you can see the noise field in action as it shifts by adding random noise. To enable UIView debugging, the following code needs to be added in the bridging header file:

@import UIKit;

@interface UIDynamicAnimator (AAPLDebugInterfaceOnly)

// Used in DropitViewController.swift file:
// lazilyCreatedDynamicAnimator.debugEnabled = true
@property (nonatomic, getter=isDebugEnabled) BOOL debugEnabled;
@end

Full source code of the demo is available here at Github:
https://github.com/sanjibahmad/Variation-on-Dropit-Demo

Video Demo

For more on what’s new in UIKit Dynamics in iOS 9, please see the WWDC 2015 video: What’s New in UIKit Dynamics and Visual Effects

* Please see this article on how to add the Swift bridging header: Adding a Swift Bridging Header

I have compiled the following resources based on my own experience and what I believe would be an effective learning path for beginners to get up to speed on iOS development.

1. Udacity

Start with the free iOS courses available at Udacity. They are not only fun and engaging but at the end will help you build 4 resume-worthy demos that you can showcase.

Additionally the following iOS specific free courses from Udacity are also recommended:

Time commitment: X months depending on your commitment

2. Ray Wenderlich

While taking the Udacity course, visit Ray Wenderlich http://www.raywenderlich.com/tutorials from time to time. Pick a topic or article that interests you and go through it.

The idea is, instead of going through everything available from A-Z, you pick something of interest and thoroughly explore it. Each article is on a particular topic and the time-investment is at most a few hours (in contrast to going through an entire book or course).

Time commitment: X hours depending on your commitment

The problem that I have experienced in learning any new technology is information retention. I found the above 2 techniques work well for me because:

  1. One path explores the area comprehensively with loads of relevant industry-specific projects, materials, demos, practice, quizzes, etc.
  2. Another path runs in parallel, diving deep into topics of personal interest for short sprints.

3. Stanford U.

Update, Jun 6, 2016: The latest course from Stanford U. “Developing iOS 9 Apps with Swift” can be found here: https://itunes.apple.com/us/course/developing-ios-9-apps-swift/id1104579961

Once the Udacity courses are done, take the Stanford U. course CS193P available for free on iTunes (https://itunes.apple.com/us/course/developing-ios-8-apps-swift/id961180099) for upping your game-level on iOS development. Some special highlights of the CS193P course that I found interesting were:

Using enums, structures, protocols, property observers, optional chaining, GCD, code re-use, OO design, MVC, autolayouts, iPhone/iPad compatibility, avoiding memory cycles, animations, internationalization, programming insights, well-designed assignments and much more. Using these in practice and specially in correct form as expected from a Stanford U. course, will definitely make you a better developer.

4. Additional Resources

Then further sharpen your axe, polish your skills and stay up-to-date with:

5. Algorithms

Useful for practicing algorithms in Swift for coding-tests/interviews. The sites below allow you to type the code solutions in Swift and run them online for evaluation.

6. Even More Resources

And here are even more resources added on request by the owners of the respective sites.
Enjoy 🙂

This is the 4th assignment from the course Developing iOS 8 Apps with Swift, Stanford University, CS193p, Winter 2015. There is one more assignment left in this course.

Platform: iOS 9, Swift: 2.1

Full source code available here at Github repository

Smashtag is a Twitter based app that allows users to:

  • perform Twitter search queries
  • view Tweet details (including images, links, users, hashtags)
  • save 100 most recent queries in a Recent tab
  • browse Tweet images in Colllection View

All the 10 Required Tasks were completed. In addition the following Extra Credit items were implemented:

  • In the Users section of your new UITableViewController, list not only users mentioned in the Tweet, but also the user who posted the Tweet in the first place.
  • When you click on a user in the Users section, search not only for Tweets that mention that user, but also for Tweets which were posted by that user.
  • Make the “most recent searches” table be editable (i.e. let the user swipe left to delete the ones they don’t like).
  • Add some UI which displays a new view controller showing a UICollectionView of the first image (or all the images if you want) in all the Tweets that match the search. When a user clicks on an image in this UICollectionView, segue to showing them the Tweet.
  • It would be cool to have “pinching” on the UICollectionView make the cell’s size get larger and smaller (i.e. showing more or fewer images).

Video Demo

The Graphing Calculator project is a continuation of the previous 2 assignments from the Stanford University CS193P course Developing iOS 8 Apps with Swift, available for free on iTunes. This is the third and final assignment in the Calculator series.

Full source code available here at Github repository

For the other 2 projects, please see:
CalculatorBrain: Assignment 2, Stanford University Winter 2015 (iOS)
Calculator: Assignment 1, Stanford University Winter 2015 (iOS)

Graphing-Calculator_cs193p_Stanford-University

This project provides graphing features in addition to the regular calculator functions. Graphs can be plotted by entering expressions where M is the independent variable. Please see examples below.

To plot M, enter:

M, Graph

To plot sin(M), enter:

M, Sin, Graph

To plot M x cos(M), enter:

M, M, cos, x, Graph

Some interesting notes

  • The CalculatorBrain is reused to calculate the values of M for graphing
  • Plot values are set in the GraphingViewController as the data source of GraphingView
  • To fix the sluggish performance when zoomed out and panned, only the number of plots required for the screen width are calculated
  • Graph scale and origin is stored in NSUserDefaults
  • Upon device rotation, the graph is centered and adjusted slightly with the width and height change ratio

Video demo

Some interesting Swift tidbits with practical code examples. Implications: use them in your projects for more readable and maintainable code.

Declaring multiple values in a single line
Multiple variables or constants can be declared in a single line using commas to separate them:

var red = 141.0, green = 185.0, blue = 230.0, alpha = 1.0

 
They can also be declared in a single line by adding the type annotation to the final variable:

var red, green, blue, alpha: Double

 
Large number readability
For large numbers, we can use underscore for better readability:

let mapRadius = 100_000

 
Using typealias for readable code
Using typealias for more readable code. For example, var program contains AnyObject, the primary purpose of creating var program is to use it as a property list. So instead of declaring:

var program: AnyObject?

 
We can typealias PropertyList = AnyObject, and use PropertyList for the var program type.

typealias PropertyList = AnyObject
var program: PropertyList?

 
Defining optional variables with nil value
When defining an unknown optional variable it doesn’t need to be explicitly set to nil. Swift automatically sets the variable to nil. For example:

var error: String? = nil // Not needed
var error: String?       // Swift automatically sets it to nil

 
Multiple optional bindings for concise and legible code
Multiple optional bindings help avoid many layers of hard to read nested code. For example,

The pyramid of nested optional bindings (hard to read):

if let firstNumber = Int("123") {
    if let secondNumber = Int("456") {
        if firstNumber < secondNumber {
            print("\(firstNumber) < \(secondNumber)")
        }
    }
}
// prints "123 < 456"

 
Multiple optional bindings (elegant):

if let firstNumber = Int("123"), secondNumber = Int("456") where firstNumber < secondNumber {
    print("\(firstNumber) < \(secondNumber)")
}
// prints "123 < 456"

 
Nil coalescing operator
Helps provide a default value if the evaluation is nil. For example,

tipPercentageForRestaurant is nil, so tipPercentage is 0.0:

var tipPercentageForRestaurant: Double?
let tipPercentage = tipPercentageForRestaurant ?? 0
print(tipPercentage)
// prints 0.0

tipPercentageForRestaurant is 0.15, so tipPercentage is 0.15

var tipPercentageForRestaurant: Double?
tipPercentageForRestaurant = 0.15
let tipPercentage = tipPercentageForRestaurant ?? 0
print(tipPercentage)
// prints 0.15

 

CalculatorBrainThis project CalculatorBrain is a continuation of the previous project Calculator: Assignment 1, Stanford University Winter 2015 (iOS)

Source code available at Github

The ViewController code is now more lean and better organized since all calculation related logic has been moved to the model.

The project covers all the required tasks and most extra credit tasks.

In addition to the features listed in the previous project Calculator, this assignment provides:

  • A separate model for all calculations
  • Additional scientific functions
  • Memory functions
  • An Undo button (which previously functioned as the Backspace button)
  • Replaces the previous History function with a better implementation
  • Provides error messages

Two items were not implemented as described in the Extra Credit Hints section in the project specifications document:

  • The error messages come from the model with full error text instead of error codes for the ViewController to translate
  • Error handling is not implemented by associating any value (a function) with UnaryOperations and BinaryOperations

Video Demo:

calculator-assignment-1-stanford-university-ios-winter-2015Provides RPL (Reverse Polish Notation) calculator, where numbers are entered first then operations. For example, to add 6 and 4, you would:

6 Enter, 4 Enter, +
or 6 Enter, 4 +

This assignment solution covers all the required tasks including the ones listed under extra credit. Solution is Swift 2.0 and iOS 9.0 compatible.

Source code available at Github

Notes:

1. Overloaded the enter function for user input, because we want add to add it the history. The enter function is also called from other places in the code where we don’t want to add to history.

2. As mentioned in the assignment hints, floating point implementation was possible to add with a single-line of code:

if (digit != ".") || (digit == "." && display.text!.rangeOfString(".") == nil)

3. Pi implementation does not use the performOperation function but inline code since it’s easy to add:

case "Ď€": displayValue = M_PI; enter()

Video Demo:

From the Course Programming Methodology CS 106A Offered at Stanford University

Having spent more hours than I am willing to admit, finally solved Karel the Robot Problem 3 (from Assignment 1).

Please don’t look at the solution until you have solved it yourself. Otherwise you will be depriving yourself of a cool mental accomplishment.

Having said that, here’s my train of thoughts as I was trying to solve the problem:

1. Thought that ignoring the checkerboard might lead to a simpler solution. Think linearly about Karel dropping beepers alternatively on each move “over a single horizontal line” till the end is reached. Later turn the horizontal line into a checkerboard. Made some progress but the solution started getting increasingly complex.

2. Realized that the core of the problem is really the turns Karel needs to make while traversing through the checkerboard. Dropping beepers at alternate locations isn’t the real problem. So I ignored the beeper issue. This lead to a cleaner solution.

3. Karel’s movement itself shouldn’t be in any if/else control statement. It makes a mess of the code because of too many if/else checks. Karel should just move forward. Then figure out which direction it should face. You can see this behavior in lines 26-29 below. Lines 31-49 shows the logic behind setting Karel’s direction.

4. Finally the beeper code is in line 17, 19. Karel moves twice in each iteration of the while loop. Line 19 checks for even-count columns in Karel’s world. Line 21 puts a last beeper for odd-count column worlds.

5. Line 15 checks for a single-count column world.

I Googled for other solutions to compare after solving the problem. Feeling happy that the solution below is 50 lines of code. If you can think of a simpler solution then please let me know.

/*
 * File: CheckerboardKarel.java
 * ----------------------------
 * When you finish writing it, the CheckerboardKarel class should draw
 * a checkerboard using beepers, as described in Assignment 1.  You
 * should make sure that your program works for all of the sample
 * worlds supplied in the starter folder.
 */

import stanford.karel.*;

public class CheckerboardKarel extends SuperKarel {

	public void run() {
		if (frontIsBlocked()) turnLeft();		
		while (frontIsClear()) {
			if (noBeepersPresent()) putBeeper();
			moveKarelForward();
			if (frontIsClear()) {
				moveKarelForward();
				if (noBeepersPresent()) putBeeper();
			}
		}
	}
	
	private void moveKarelForward() {
		move();
		setKarelsDirection();
	}
	
	private void setKarelsDirection() {
		if (facingEast()) {
			if (frontIsBlocked()) {
				turnLeft();
			}
		} else if (facingWest()) {
			if (frontIsBlocked()) {
				turnRight();
			}
		} else if (facingNorth()) {
			if (rightIsBlocked()) {
				if (leftIsClear()) {
					turnLeft();	
				}				
			} else if (leftIsBlocked()) {
				turnRight();
			}
		}
	}
}

Testing Checkerboard Karel in different worlds:

Platform: iOS 8.x or later
Device: iPhone
Language: Swift
Motivation: when user unplugs their headphones, you wan’t to stop playing audio (iTunes like behavior) in your app

The following code snippet shows how to detect if headphones are plugged in (when the app starts or is woken up). The println() command below shows the state of the headphone connection.

let currentRoute = AVAudioSession.sharedInstance().currentRoute
if currentRoute.outputs != nil {
    for description in currentRoute.outputs {
        if description.portType == AVAudioSessionPortHeadphones {
            println("headphone plugged in")
        } else {
            println("headphone pulled out")
        }
    }
} else {
    println("requires connection to device")
}

In Line 4 above, we are checking if portType equals AVAudioSessionPortHeadphones. The full list of output port types are listed below:

  • AVAudioSessionPortLineOut
  • AVAudioSessionPortHeadphones
  • AVAudioSessionPortBluetoothA2DP
  • AVAudioSessionPortBuiltInReceiver
  • AVAudioSessionPortBuiltInSpeaker
  • AVAudioSessionPortHDMI
  • AVAudioSessionPortAirPlay
  • AVAudioSessionPortBluetoothLE

However while the app is running you can’t use the above code snippet to detect active changes in headphones connection. You will need to setup a notification observer for AVAudioSessionRouteChangeNotification in your app with the code below.

NSNotificationCenter.defaultCenter().addObserver(
    self,
    selector: "audioRouteChangeListener:",
    name: AVAudioSessionRouteChangeNotification,
    object: nil)

In line 3 above, the audioRouteChangeListener: is the method that will get notified once a change in headphones connection occurs. The println() statements below show the change in headphones connection to the device.

dynamic private func audioRouteChangeListener(notification:NSNotification) {
    let audioRouteChangeReason = notification.userInfo![AVAudioSessionRouteChangeReasonKey] as UInt

    switch audioRouteChangeReason {
    case AVAudioSessionRouteChangeReason.NewDeviceAvailable.rawValue:
        println("headphone plugged in")
    case AVAudioSessionRouteChangeReason.OldDeviceUnavailable.rawValue:
        println("headphone pulled out")
    default:
        break
    }
}

In line 4 above, we are checking switch-case values for AVAudioSessionRouteChangeReasonKey (identified by the variable audioRouteChangeReason). We are interested in two cases, NewDeviceAvailable (headphones plugged in) and OldDeviceUnavailable (headphone pulled out). The full list of cases are provided below:

  • Unknown
  • NewDeviceAvailable
  • OldDeviceUnavailable
  • CategoryChange
  • Override
  • WakeFromSleep
  • NoSuitableRouteForCategory
  • RouteConfigurationChange

A demo app utilizing the code above can be found here:
https://github.com/sanjibahmad/Is-Headphone-Plugged-In

Here’s a video showing how the app works:

 

Thanks to Udacity for the motivation to write this.

The problem: From page 42, Exercise 3, Chapter 3, Programming Erlang by Joe Armstrong

Try representing a house using a tuple and a street using a list of houses. Make sure you can pack and unpack the data in the representations.

This is a very simple problem. Each house is a tuple, and the street is a list of tuples (houses). We create 4 houses that belongs to 4 famous fictional characters with varying reputation 🙂 Batman, Donald Duck, Sherlock Holmes and Spongebob Squarepants. We pack them in the street list (line 1) and then unpack them. First we get Batman’s house (line 2), then the resident (line 4).

Erlang/OTP 17 [erts-6.3]  [64-bit] [smp:8:8] [async-threads:10] [hipe] [kernel-poll:false] [dtrace]

Eshell V6.3  (abort with ^G)
1> Street = [{house, {resident, "Batman"},{address, "Wayne Manor, Gotham City"}}, {house, {resident, "Donald Duck"}, {address, "1313 Webfoot Walk, Duckburg, Calisota"}}, {house, {resident, "Sherlock Holmes"}, {address, "221B Baker Street"}}, {house, {resident, "Spongebob SquarePants"}, {address, "124 Conch Street, Bikini Bottom"}}].
[{house,{resident,"Batman"},
        {address,"Wayne Manor, Gotham City"}},
 {house,{resident,"Donald Duck"},
        {address,"1313 Webfoot Walk, Duckburg, Calisota"}},
 {house,{resident,"Sherlock Holmes"},
        {address,"221B Baker Street"}},
 {house,{resident,"Spongebob SquarePants"},
        {address,"124 Conch Street, Bikini Bottom"}}]
2> [HouseBatman,_,_,_] = Street.
[{house,{resident,"Batman"},
        {address,"Wayne Manor, Gotham City"}},
 {house,{resident,"Donald Duck"},
        {address,"1313 Webfoot Walk, Duckburg, Calisota"}},
 {house,{resident,"Sherlock Holmes"},
        {address,"221B Baker Street"}},
 {house,{resident,"Spongebob SquarePants"},
        {address,"124 Conch Street, Bikini Bottom"}}]
3> HouseBatman.
{house,{resident,"Batman"},
       {address,"Wayne Manor, Gotham City"}}
4> {_,HouseBatmanResident,_} = HouseBatman.
{house,{resident,"Batman"},
       {address,"Wayne Manor, Gotham City"}}
5> HouseBatmanResident.
{resident,"Batman"}
6>