cs193p - lecture 18web.stanford.edu/class/cs193p/cgi-bin/drupal/system/files/lectures/1… ·...

122
CS193P - Lecture 18 iPhone Application Development Unit Testing Fun with Objective-C Localization Mailbag 1 Monday, March 15, 2010

Upload: others

Post on 29-Sep-2020

7 views

Category:

Documents


0 download

TRANSCRIPT

Page 1: CS193P - Lecture 18web.stanford.edu/class/cs193p/cgi-bin/drupal/system/files/lectures/1… · •Ideally written along with new code •Test-driven development Write tests first Fill

CS193P - Lecture 18iPhone Application Development

Unit TestingFun with Objective-CLocalizationMailbag

1Monday, March 15, 2010

Page 2: CS193P - Lecture 18web.stanford.edu/class/cs193p/cgi-bin/drupal/system/files/lectures/1… · •Ideally written along with new code •Test-driven development Write tests first Fill

Unit Testing

2Monday, March 15, 2010

Page 3: CS193P - Lecture 18web.stanford.edu/class/cs193p/cgi-bin/drupal/system/files/lectures/1… · •Ideally written along with new code •Test-driven development Write tests first Fill

What Are Unit Tests?• Test specific areas of functionality• Minimal external dependencies• Run frequently during development

3Monday, March 15, 2010

Page 4: CS193P - Lecture 18web.stanford.edu/class/cs193p/cgi-bin/drupal/system/files/lectures/1… · •Ideally written along with new code •Test-driven development Write tests first Fill

Who Writes Unit Tests?• You do!• Ideally written along with new code• Test-driven development

■ Write tests first■ Fill in the implementation until tests pass■ Rinse & repeat

4Monday, March 15, 2010

Page 5: CS193P - Lecture 18web.stanford.edu/class/cs193p/cgi-bin/drupal/system/files/lectures/1… · •Ideally written along with new code •Test-driven development Write tests first Fill

Running Unit Tests• Automate so you don't have to explicitly run tests• Many testing frameworks can run tests every time you build

• Just as compiler checks syntax, unit tests check semantics

5Monday, March 15, 2010

Page 6: CS193P - Lecture 18web.stanford.edu/class/cs193p/cgi-bin/drupal/system/files/lectures/1… · •Ideally written along with new code •Test-driven development Write tests first Fill

Why Unit Test?

6Monday, March 15, 2010

Page 7: CS193P - Lecture 18web.stanford.edu/class/cs193p/cgi-bin/drupal/system/files/lectures/1… · •Ideally written along with new code •Test-driven development Write tests first Fill

Why Unit Test?• Fewer bugs

■ More confidence that you're shipping a high quality product

6Monday, March 15, 2010

Page 8: CS193P - Lecture 18web.stanford.edu/class/cs193p/cgi-bin/drupal/system/files/lectures/1… · •Ideally written along with new code •Test-driven development Write tests first Fill

Why Unit Test?• Fewer bugs

■ More confidence that you're shipping a high quality product

• Find bugs early■ Bugs are easier (and cheaper) to fix early in development

6Monday, March 15, 2010

Page 9: CS193P - Lecture 18web.stanford.edu/class/cs193p/cgi-bin/drupal/system/files/lectures/1… · •Ideally written along with new code •Test-driven development Write tests first Fill

Why Unit Test?• Fewer bugs

■ More confidence that you're shipping a high quality product

• Find bugs early■ Bugs are easier (and cheaper) to fix early in development

• Avoid regressions■ Ensure that changing one piece of code doesn't break another

6Monday, March 15, 2010

Page 10: CS193P - Lecture 18web.stanford.edu/class/cs193p/cgi-bin/drupal/system/files/lectures/1… · •Ideally written along with new code •Test-driven development Write tests first Fill

Why Unit Test?• Fewer bugs

■ More confidence that you're shipping a high quality product

• Find bugs early■ Bugs are easier (and cheaper) to fix early in development

• Avoid regressions■ Ensure that changing one piece of code doesn't break another

• Document your code■ How is a method intended to be used? Check out the tests...

6Monday, March 15, 2010

Page 11: CS193P - Lecture 18web.stanford.edu/class/cs193p/cgi-bin/drupal/system/files/lectures/1… · •Ideally written along with new code •Test-driven development Write tests first Fill

Why Unit Test?• Fewer bugs

■ More confidence that you're shipping a high quality product

• Find bugs early■ Bugs are easier (and cheaper) to fix early in development

• Avoid regressions■ Ensure that changing one piece of code doesn't break another

• Document your code■ How is a method intended to be used? Check out the tests...

• Encourage good design■ Spaghetti code is hard to test! Design with testability in mind

6Monday, March 15, 2010

Page 12: CS193P - Lecture 18web.stanford.edu/class/cs193p/cgi-bin/drupal/system/files/lectures/1… · •Ideally written along with new code •Test-driven development Write tests first Fill

Unit Testing Frameworks• Family of similar frameworks for testing various languages

■ JUnit, NUnit, PyUnit...

• OCUnit for Objective-C■ Ships with Mac OS X developer tools, integrates with Xcode■ Included with iPhone SDK as of 2.2

7Monday, March 15, 2010

Page 13: CS193P - Lecture 18web.stanford.edu/class/cs193p/cgi-bin/drupal/system/files/lectures/1… · •Ideally written along with new code •Test-driven development Write tests first Fill

Basics of OCUnit• SenTestCase is abstract test case superclass• Automatically runs methods that begin with "test"• Macros for asserting conditions during tests

■ STAssertNotNil(someObject, @"Some object was nil");■ See SenTestCase.h for more

• -setUp and -tearDown methods run before and after each test

8Monday, March 15, 2010

Page 14: CS193P - Lecture 18web.stanford.edu/class/cs193p/cgi-bin/drupal/system/files/lectures/1… · •Ideally written along with new code •Test-driven development Write tests first Fill

Defining A New Test Case Class

9Monday, March 15, 2010

Page 15: CS193P - Lecture 18web.stanford.edu/class/cs193p/cgi-bin/drupal/system/files/lectures/1… · •Ideally written along with new code •Test-driven development Write tests first Fill

Defining A New Test Case Class#import <SenTestingKit/SenTestingKit.h>

@class Foo;

@interface FooTests : SenTestCase {Foo *foo;

}@end

9Monday, March 15, 2010

Page 16: CS193P - Lecture 18web.stanford.edu/class/cs193p/cgi-bin/drupal/system/files/lectures/1… · •Ideally written along with new code •Test-driven development Write tests first Fill

Preparing Tests

10Monday, March 15, 2010

Page 17: CS193P - Lecture 18web.stanford.edu/class/cs193p/cgi-bin/drupal/system/files/lectures/1… · •Ideally written along with new code •Test-driven development Write tests first Fill

Preparing Tests @implementation FooTests

- (void)setUp {// Every test will have its own Foo instancefoo = [[Foo alloc] init];

}

- (void)tearDown {[foo release];

}

...

@end

10Monday, March 15, 2010

Page 18: CS193P - Lecture 18web.stanford.edu/class/cs193p/cgi-bin/drupal/system/files/lectures/1… · •Ideally written along with new code •Test-driven development Write tests first Fill

Adding Tests

11Monday, March 15, 2010

Page 19: CS193P - Lecture 18web.stanford.edu/class/cs193p/cgi-bin/drupal/system/files/lectures/1… · •Ideally written along with new code •Test-driven development Write tests first Fill

Adding Tests@implementation FooTests

...

- (void)testCreateFoo {STAssertNotNil(foo, @"Couldn't create Foo");

}

- (void)testSetBar {Bar *bar = ...;foo.bar = bar;STAssertEqualObjects(foo.bar, bar, @"Couldn't set foo.bar");

}

...

@end

11Monday, March 15, 2010

Page 20: CS193P - Lecture 18web.stanford.edu/class/cs193p/cgi-bin/drupal/system/files/lectures/1… · •Ideally written along with new code •Test-driven development Write tests first Fill

Testing Error Conditions

12Monday, March 15, 2010

Page 21: CS193P - Lecture 18web.stanford.edu/class/cs193p/cgi-bin/drupal/system/files/lectures/1… · •Ideally written along with new code •Test-driven development Write tests first Fill

Testing Error Conditions@implementation FooTests

...

- (void)testOutOfBoundsAccess {STAssertNil([foo barAtIndex:99], @"Index 99 should be nil");

}

...

@end

12Monday, March 15, 2010

Page 22: CS193P - Lecture 18web.stanford.edu/class/cs193p/cgi-bin/drupal/system/files/lectures/1… · •Ideally written along with new code •Test-driven development Write tests first Fill

Demo:Unit Testing an iPhone App

13Monday, March 15, 2010

Page 23: CS193P - Lecture 18web.stanford.edu/class/cs193p/cgi-bin/drupal/system/files/lectures/1… · •Ideally written along with new code •Test-driven development Write tests first Fill

When Does Unit Testing Make Sense?

14Monday, March 15, 2010

Page 24: CS193P - Lecture 18web.stanford.edu/class/cs193p/cgi-bin/drupal/system/files/lectures/1… · •Ideally written along with new code •Test-driven development Write tests first Fill

When Does Unit Testing Make Sense?• Always be conscious of the return on investment

■ Benefit of the test versus time to create and maintain?

14Monday, March 15, 2010

Page 25: CS193P - Lecture 18web.stanford.edu/class/cs193p/cgi-bin/drupal/system/files/lectures/1… · •Ideally written along with new code •Test-driven development Write tests first Fill

When Does Unit Testing Make Sense?• Always be conscious of the return on investment

■ Benefit of the test versus time to create and maintain?

• Some types of code are notoriously difficult to test■ Networking■ Databases■ Often possible to test a subset of behavior and still benefit

14Monday, March 15, 2010

Page 26: CS193P - Lecture 18web.stanford.edu/class/cs193p/cgi-bin/drupal/system/files/lectures/1… · •Ideally written along with new code •Test-driven development Write tests first Fill

Unit Testing Philosophy

15Monday, March 15, 2010

Page 27: CS193P - Lecture 18web.stanford.edu/class/cs193p/cgi-bin/drupal/system/files/lectures/1… · •Ideally written along with new code •Test-driven development Write tests first Fill

Unit Testing Philosophy• Keep tests short, lightweight, fast

15Monday, March 15, 2010

Page 28: CS193P - Lecture 18web.stanford.edu/class/cs193p/cgi-bin/drupal/system/files/lectures/1… · •Ideally written along with new code •Test-driven development Write tests first Fill

Unit Testing Philosophy• Keep tests short, lightweight, fast• Test individual methods, not end-to-end behavior

15Monday, March 15, 2010

Page 29: CS193P - Lecture 18web.stanford.edu/class/cs193p/cgi-bin/drupal/system/files/lectures/1… · •Ideally written along with new code •Test-driven development Write tests first Fill

Unit Testing Philosophy• Keep tests short, lightweight, fast• Test individual methods, not end-to-end behavior• Find a new bug? Write a new test before you fix it

15Monday, March 15, 2010

Page 30: CS193P - Lecture 18web.stanford.edu/class/cs193p/cgi-bin/drupal/system/files/lectures/1… · •Ideally written along with new code •Test-driven development Write tests first Fill

Unit Testing Philosophy• Keep tests short, lightweight, fast• Test individual methods, not end-to-end behavior• Find a new bug? Write a new test before you fix it• Complement (rather than replace) other types of tests

■ http://www.friday.com/bbum/2005/09/24/unit-testing/

15Monday, March 15, 2010

Page 31: CS193P - Lecture 18web.stanford.edu/class/cs193p/cgi-bin/drupal/system/files/lectures/1… · •Ideally written along with new code •Test-driven development Write tests first Fill

Fun with Objective-C

16Monday, March 15, 2010

Page 32: CS193P - Lecture 18web.stanford.edu/class/cs193p/cgi-bin/drupal/system/files/lectures/1… · •Ideally written along with new code •Test-driven development Write tests first Fill

The Objective-C Runtime• How does OCUnit find all the methods that begin with “test”?• Any other cool tricks?

17Monday, March 15, 2010

Page 33: CS193P - Lecture 18web.stanford.edu/class/cs193p/cgi-bin/drupal/system/files/lectures/1… · •Ideally written along with new code •Test-driven development Write tests first Fill

/usr/include/objc

18Monday, March 15, 2010

Page 34: CS193P - Lecture 18web.stanford.edu/class/cs193p/cgi-bin/drupal/system/files/lectures/1… · •Ideally written along with new code •Test-driven development Write tests first Fill

/usr/include/objc• <objc/objc.h>

■ id, Nil, nil, BOOL, YES, NO

18Monday, March 15, 2010

Page 35: CS193P - Lecture 18web.stanford.edu/class/cs193p/cgi-bin/drupal/system/files/lectures/1… · •Ideally written along with new code •Test-driven development Write tests first Fill

/usr/include/objc• <objc/objc.h>

■ id, Nil, nil, BOOL, YES, NO

• <objc/message.h>■ objc_msgSend() and friends

18Monday, March 15, 2010

Page 36: CS193P - Lecture 18web.stanford.edu/class/cs193p/cgi-bin/drupal/system/files/lectures/1… · •Ideally written along with new code •Test-driven development Write tests first Fill

/usr/include/objc• <objc/objc.h>

■ id, Nil, nil, BOOL, YES, NO

• <objc/message.h>■ objc_msgSend() and friends

• <objc/runtime.h>■ Inspect and manipulate classes, protocols, methods■ Add and replace methods at runtime

18Monday, March 15, 2010

Page 37: CS193P - Lecture 18web.stanford.edu/class/cs193p/cgi-bin/drupal/system/files/lectures/1… · •Ideally written along with new code •Test-driven development Write tests first Fill

Inspecting Methods

19Monday, March 15, 2010

Page 38: CS193P - Lecture 18web.stanford.edu/class/cs193p/cgi-bin/drupal/system/files/lectures/1… · •Ideally written along with new code •Test-driven development Write tests first Fill

Inspecting Methods• Copy all methods for a classMethod *class_copyMethodList(Class cls, unsigned int *outCount);

19Monday, March 15, 2010

Page 39: CS193P - Lecture 18web.stanford.edu/class/cs193p/cgi-bin/drupal/system/files/lectures/1… · •Ideally written along with new code •Test-driven development Write tests first Fill

Inspecting Methods• Copy all methods for a class

• Get attributes for a method

Method *class_copyMethodList(Class cls, unsigned int *outCount);

SEL method_getName(Method m);IMP method_getImplementation(Method m);char *method_copyReturnType(Method m);...

19Monday, March 15, 2010

Page 40: CS193P - Lecture 18web.stanford.edu/class/cs193p/cgi-bin/drupal/system/files/lectures/1… · •Ideally written along with new code •Test-driven development Write tests first Fill

Demo:Inspecting Methods

20Monday, March 15, 2010

Page 41: CS193P - Lecture 18web.stanford.edu/class/cs193p/cgi-bin/drupal/system/files/lectures/1… · •Ideally written along with new code •Test-driven development Write tests first Fill

Playing With Fire

21Monday, March 15, 2010

Page 42: CS193P - Lecture 18web.stanford.edu/class/cs193p/cgi-bin/drupal/system/files/lectures/1… · •Ideally written along with new code •Test-driven development Write tests first Fill

Playing With Fire• Adding a method to a classBOOL class_addMethod(Class cls, SEL name, IMP imp, const char *types);

21Monday, March 15, 2010

Page 43: CS193P - Lecture 18web.stanford.edu/class/cs193p/cgi-bin/drupal/system/files/lectures/1… · •Ideally written along with new code •Test-driven development Write tests first Fill

Playing With Fire• Adding a method to a class

• Replacing the implementation for a method

BOOL class_addMethod(Class cls, SEL name, IMP imp, const char *types);

IMP method_setImplementation(Method method, IMP imp);

21Monday, March 15, 2010

Page 44: CS193P - Lecture 18web.stanford.edu/class/cs193p/cgi-bin/drupal/system/files/lectures/1… · •Ideally written along with new code •Test-driven development Write tests first Fill

Playing With Fire• Adding a method to a class

• Replacing the implementation for a method

• Method swizzling

BOOL class_addMethod(Class cls, SEL name, IMP imp, const char *types);

IMP method_setImplementation(Method method, IMP imp);

void method_exchangeImplementations(Method m1, Method m2);

21Monday, March 15, 2010

Page 45: CS193P - Lecture 18web.stanford.edu/class/cs193p/cgi-bin/drupal/system/files/lectures/1… · •Ideally written along with new code •Test-driven development Write tests first Fill

Method Swizzling

22Monday, March 15, 2010

Page 46: CS193P - Lecture 18web.stanford.edu/class/cs193p/cgi-bin/drupal/system/files/lectures/1… · •Ideally written along with new code •Test-driven development Write tests first Fill

Method Swizzling• What if you want to override a method in a category while

still making use of the original method?

22Monday, March 15, 2010

Page 47: CS193P - Lecture 18web.stanford.edu/class/cs193p/cgi-bin/drupal/system/files/lectures/1… · •Ideally written along with new code •Test-driven development Write tests first Fill

Method Swizzling• What if you want to override a method in a category while

still making use of the original method?■ Can’t call super, a category isn’t a subclass

22Monday, March 15, 2010

Page 48: CS193P - Lecture 18web.stanford.edu/class/cs193p/cgi-bin/drupal/system/files/lectures/1… · •Ideally written along with new code •Test-driven development Write tests first Fill

Method Swizzling• What if you want to override a method in a category while

still making use of the original method?■ Can’t call super, a category isn’t a subclass

• Define a new method, swizzle it into place

22Monday, March 15, 2010

Page 49: CS193P - Lecture 18web.stanford.edu/class/cs193p/cgi-bin/drupal/system/files/lectures/1… · •Ideally written along with new code •Test-driven development Write tests first Fill

Method Swizzling• What if you want to override a method in a category while

still making use of the original method?■ Can’t call super, a category isn’t a subclass

• Define a new method, swizzle it into placeMethod existingMethod = ...;Method fancyNewMethod = ...;method_exchangeImplementations(existingMethod, fancyNewMethod);

22Monday, March 15, 2010

Page 50: CS193P - Lecture 18web.stanford.edu/class/cs193p/cgi-bin/drupal/system/files/lectures/1… · •Ideally written along with new code •Test-driven development Write tests first Fill

Method Swizzling• What if you want to override a method in a category while

still making use of the original method?■ Can’t call super, a category isn’t a subclass

• Define a new method, swizzle it into placeMethod existingMethod = ...;Method fancyNewMethod = ...;method_exchangeImplementations(existingMethod, fancyNewMethod);

- (void)fancyNewMethod{

// This looks like it will cause an infinite loop...// Once swizzled, it will actually invoke -existingMethod![self fancyNewMethod];

// Perform additional work here}

22Monday, March 15, 2010

Page 51: CS193P - Lecture 18web.stanford.edu/class/cs193p/cgi-bin/drupal/system/files/lectures/1… · •Ideally written along with new code •Test-driven development Write tests first Fill

Demo:Method Swizzling

23Monday, March 15, 2010

Page 52: CS193P - Lecture 18web.stanford.edu/class/cs193p/cgi-bin/drupal/system/files/lectures/1… · •Ideally written along with new code •Test-driven development Write tests first Fill

Why is this dangerous?

24Monday, March 15, 2010

Page 53: CS193P - Lecture 18web.stanford.edu/class/cs193p/cgi-bin/drupal/system/files/lectures/1… · •Ideally written along with new code •Test-driven development Write tests first Fill

Why is this dangerous?• Other code may be dependent on the original implementation

■ Perhaps code you didn’t even write?

24Monday, March 15, 2010

Page 54: CS193P - Lecture 18web.stanford.edu/class/cs193p/cgi-bin/drupal/system/files/lectures/1… · •Ideally written along with new code •Test-driven development Write tests first Fill

Why is this dangerous?• Other code may be dependent on the original implementation

■ Perhaps code you didn’t even write?

• Can cause unexpected behavior, bizarre bugs, crashes■ This has caused some popular apps to break on iPhone OS 3.0

24Monday, March 15, 2010

Page 55: CS193P - Lecture 18web.stanford.edu/class/cs193p/cgi-bin/drupal/system/files/lectures/1… · •Ideally written along with new code •Test-driven development Write tests first Fill

Why is this dangerous?• Other code may be dependent on the original implementation

■ Perhaps code you didn’t even write?

• Can cause unexpected behavior, bizarre bugs, crashes■ This has caused some popular apps to break on iPhone OS 3.0

• Writing “clever” code is fun until you have to debug it

24Monday, March 15, 2010

Page 56: CS193P - Lecture 18web.stanford.edu/class/cs193p/cgi-bin/drupal/system/files/lectures/1… · •Ideally written along with new code •Test-driven development Write tests first Fill

Why is this dangerous?• Other code may be dependent on the original implementation

■ Perhaps code you didn’t even write?

• Can cause unexpected behavior, bizarre bugs, crashes■ This has caused some popular apps to break on iPhone OS 3.0

• Writing “clever” code is fun until you have to debug it• Never ship an app that swizzles methods on system classes

24Monday, March 15, 2010

Page 57: CS193P - Lecture 18web.stanford.edu/class/cs193p/cgi-bin/drupal/system/files/lectures/1… · •Ideally written along with new code •Test-driven development Write tests first Fill

Objective-C 2.0 Runtime Reference• http://developer.apple.com/DOCUMENTATION/Cocoa/

Reference/ObjCRuntimeRef/Reference/reference.html

25Monday, March 15, 2010

Page 58: CS193P - Lecture 18web.stanford.edu/class/cs193p/cgi-bin/drupal/system/files/lectures/1… · •Ideally written along with new code •Test-driven development Write tests first Fill

class-dump

26Monday, March 15, 2010

Page 59: CS193P - Lecture 18web.stanford.edu/class/cs193p/cgi-bin/drupal/system/files/lectures/1… · •Ideally written along with new code •Test-driven development Write tests first Fill

class-dump• Inspect the classes and methods of an Objective-C binary

26Monday, March 15, 2010

Page 60: CS193P - Lecture 18web.stanford.edu/class/cs193p/cgi-bin/drupal/system/files/lectures/1… · •Ideally written along with new code •Test-driven development Write tests first Fill

class-dump• Inspect the classes and methods of an Objective-C binary• Fascinating to see how a complex application is architected

■ Especially one that you didn’t write!

26Monday, March 15, 2010

Page 61: CS193P - Lecture 18web.stanford.edu/class/cs193p/cgi-bin/drupal/system/files/lectures/1… · •Ideally written along with new code •Test-driven development Write tests first Fill

class-dump• Inspect the classes and methods of an Objective-C binary• Fascinating to see how a complex application is architected

■ Especially one that you didn’t write!

• As usual, this can be used for evil purposes as well■ Discover and use private methods in a framework

26Monday, March 15, 2010

Page 62: CS193P - Lecture 18web.stanford.edu/class/cs193p/cgi-bin/drupal/system/files/lectures/1… · •Ideally written along with new code •Test-driven development Write tests first Fill

“Calling unpublished APIs is like jaywalking...”

27Monday, March 15, 2010

Page 63: CS193P - Lecture 18web.stanford.edu/class/cs193p/cgi-bin/drupal/system/files/lectures/1… · •Ideally written along with new code •Test-driven development Write tests first Fill

“Calling unpublished APIs is like jaywalking across 280”

28Monday, March 15, 2010

Page 64: CS193P - Lecture 18web.stanford.edu/class/cs193p/cgi-bin/drupal/system/files/lectures/1… · •Ideally written along with new code •Test-driven development Write tests first Fill

The Problem with Using Private APIs

29Monday, March 15, 2010

Page 65: CS193P - Lecture 18web.stanford.edu/class/cs193p/cgi-bin/drupal/system/files/lectures/1… · •Ideally written along with new code •Test-driven development Write tests first Fill

The Problem with Using Private APIs• Framework APIs are kept private for one of a few reasons:

29Monday, March 15, 2010

Page 66: CS193P - Lecture 18web.stanford.edu/class/cs193p/cgi-bin/drupal/system/files/lectures/1… · •Ideally written along with new code •Test-driven development Write tests first Fill

The Problem with Using Private APIs• Framework APIs are kept private for one of a few reasons:

■ They’re not done yet (and will probably change)

29Monday, March 15, 2010

Page 67: CS193P - Lecture 18web.stanford.edu/class/cs193p/cgi-bin/drupal/system/files/lectures/1… · •Ideally written along with new code •Test-driven development Write tests first Fill

The Problem with Using Private APIs• Framework APIs are kept private for one of a few reasons:

■ They’re not done yet (and will probably change)■ They’re never going to be public (and may disappear)

29Monday, March 15, 2010

Page 68: CS193P - Lecture 18web.stanford.edu/class/cs193p/cgi-bin/drupal/system/files/lectures/1… · •Ideally written along with new code •Test-driven development Write tests first Fill

The Problem with Using Private APIs• Framework APIs are kept private for one of a few reasons:

■ They’re not done yet (and will probably change)■ They’re never going to be public (and may disappear)

• Not just because Apple wants to hide cool stuff from you

29Monday, March 15, 2010

Page 69: CS193P - Lecture 18web.stanford.edu/class/cs193p/cgi-bin/drupal/system/files/lectures/1… · •Ideally written along with new code •Test-driven development Write tests first Fill

The Problem with Using Private APIs• Framework APIs are kept private for one of a few reasons:

■ They’re not done yet (and will probably change)■ They’re never going to be public (and may disappear)

• Not just because Apple wants to hide cool stuff from you• If your app depends on a private API that goes away...

29Monday, March 15, 2010

Page 70: CS193P - Lecture 18web.stanford.edu/class/cs193p/cgi-bin/drupal/system/files/lectures/1… · •Ideally written along with new code •Test-driven development Write tests first Fill

The Problem with Using Private APIs• Framework APIs are kept private for one of a few reasons:

■ They’re not done yet (and will probably change)■ They’re never going to be public (and may disappear)

• Not just because Apple wants to hide cool stuff from you• If your app depends on a private API that goes away...

■ At best, your app won’t work correctly anymore

29Monday, March 15, 2010

Page 71: CS193P - Lecture 18web.stanford.edu/class/cs193p/cgi-bin/drupal/system/files/lectures/1… · •Ideally written along with new code •Test-driven development Write tests first Fill

The Problem with Using Private APIs• Framework APIs are kept private for one of a few reasons:

■ They’re not done yet (and will probably change)■ They’re never going to be public (and may disappear)

• Not just because Apple wants to hide cool stuff from you• If your app depends on a private API that goes away...

■ At best, your app won’t work correctly anymore■ More often, your app will just crash

29Monday, March 15, 2010

Page 72: CS193P - Lecture 18web.stanford.edu/class/cs193p/cgi-bin/drupal/system/files/lectures/1… · •Ideally written along with new code •Test-driven development Write tests first Fill

Localization

30Monday, March 15, 2010

Page 73: CS193P - Lecture 18web.stanford.edu/class/cs193p/cgi-bin/drupal/system/files/lectures/1… · •Ideally written along with new code •Test-driven development Write tests first Fill

Your International Application• Multiple languages and locales in a single built application• Keep localized resources separate from everything else

■ Strings■ Images■ User interfaces (in NIBs)

31Monday, March 15, 2010

Page 74: CS193P - Lecture 18web.stanford.edu/class/cs193p/cgi-bin/drupal/system/files/lectures/1… · •Ideally written along with new code •Test-driven development Write tests first Fill

Where Do Localized Resources Go?• MyApp.app/

■ MyApp■ English.lproj/

■ Localizable.strings■ MyView.nib

■ Japanese.lproj/■ Localizable.strings■ MyView.nib

32Monday, March 15, 2010

Page 75: CS193P - Lecture 18web.stanford.edu/class/cs193p/cgi-bin/drupal/system/files/lectures/1… · •Ideally written along with new code •Test-driven development Write tests first Fill

Two Steps• Internationalization (i18n)

■ Prepare your app to be used in different languages and locales

• Localization (l10n)■ Add localized data for specific languages and locales

33Monday, March 15, 2010

Page 76: CS193P - Lecture 18web.stanford.edu/class/cs193p/cgi-bin/drupal/system/files/lectures/1… · •Ideally written along with new code •Test-driven development Write tests first Fill

NSString to the Rescue• Interconverts with dozens of encodings• Saves you from having to deal with complexities of text• Remember encoding when reading data from disk or web

- (id)initWithData:(NSData *)data encoding:(NSStringEncoding)encoding;

34Monday, March 15, 2010

Page 77: CS193P - Lecture 18web.stanford.edu/class/cs193p/cgi-bin/drupal/system/files/lectures/1… · •Ideally written along with new code •Test-driven development Write tests first Fill

Localized Strings• For user-visible strings in your application code• Map from an unlocalized key to a localized string• Stored in .strings files

■ Key-value pairs■ Use UTF-16 for encoding

35Monday, March 15, 2010

Page 78: CS193P - Lecture 18web.stanford.edu/class/cs193p/cgi-bin/drupal/system/files/lectures/1… · •Ideally written along with new code •Test-driven development Write tests first Fill

Strings File Example• en.lproj/Greetings.strings

"Hello" = "Hello";"Welcome to %@" = "Welcome to %@";"Blah %@ blah %@!" = "Blah %@ blah %@";

• fr.lproj/Greetings.strings

"Hello" = "Bonjour";"Welcome to %@" = "Bienvenue a %@";"Blah %@ blah %@" = "Blah %2$@ %1$@ blah";

36Monday, March 15, 2010

Page 79: CS193P - Lecture 18web.stanford.edu/class/cs193p/cgi-bin/drupal/system/files/lectures/1… · •Ideally written along with new code •Test-driven development Write tests first Fill

Accessing Localized Strings// By default, uses Localizable.stringsNSLocalizedString(@"Hello", @"Greeting for welcome screen");

// Specify a table, uses Greetings.stringsNSLocalizedStringFromTable(@"Hello", @"Greetings", @"Greeting for welcome screen");

37Monday, March 15, 2010

Page 80: CS193P - Lecture 18web.stanford.edu/class/cs193p/cgi-bin/drupal/system/files/lectures/1… · •Ideally written along with new code •Test-driven development Write tests first Fill

genstrings• Tool to scan your code and produce a .strings file• Inserts comments found in code as clues to localizer• Run the tool over your *.m files

38Monday, March 15, 2010

Page 81: CS193P - Lecture 18web.stanford.edu/class/cs193p/cgi-bin/drupal/system/files/lectures/1… · •Ideally written along with new code •Test-driven development Write tests first Fill

Other Resources• NSBundle resource methods automatically use the best

available localization• Nib loading does the same

39Monday, March 15, 2010

Page 82: CS193P - Lecture 18web.stanford.edu/class/cs193p/cgi-bin/drupal/system/files/lectures/1… · •Ideally written along with new code •Test-driven development Write tests first Fill

Internationalizing NIBs• Plan for different string lengths in different languages

■ Good idea to start with German...

40Monday, March 15, 2010

Page 83: CS193P - Lecture 18web.stanford.edu/class/cs193p/cgi-bin/drupal/system/files/lectures/1… · •Ideally written along with new code •Test-driven development Write tests first Fill

Localizing a Resource

41Monday, March 15, 2010

Page 84: CS193P - Lecture 18web.stanford.edu/class/cs193p/cgi-bin/drupal/system/files/lectures/1… · •Ideally written along with new code •Test-driven development Write tests first Fill

Localizing a Resource

41Monday, March 15, 2010

Page 85: CS193P - Lecture 18web.stanford.edu/class/cs193p/cgi-bin/drupal/system/files/lectures/1… · •Ideally written along with new code •Test-driven development Write tests first Fill

Localizing a Resource

41Monday, March 15, 2010

Page 86: CS193P - Lecture 18web.stanford.edu/class/cs193p/cgi-bin/drupal/system/files/lectures/1… · •Ideally written along with new code •Test-driven development Write tests first Fill

NSLocale• Measurements• Currency• Number formatting• Calendar and date format• Country information

42Monday, March 15, 2010

Page 87: CS193P - Lecture 18web.stanford.edu/class/cs193p/cgi-bin/drupal/system/files/lectures/1… · •Ideally written along with new code •Test-driven development Write tests first Fill

Opening the Mailbag...

43Monday, March 15, 2010

Page 88: CS193P - Lecture 18web.stanford.edu/class/cs193p/cgi-bin/drupal/system/files/lectures/1… · •Ideally written along with new code •Test-driven development Write tests first Fill

44Monday, March 15, 2010

Page 89: CS193P - Lecture 18web.stanford.edu/class/cs193p/cgi-bin/drupal/system/files/lectures/1… · •Ideally written along with new code •Test-driven development Write tests first Fill

44Monday, March 15, 2010

Page 90: CS193P - Lecture 18web.stanford.edu/class/cs193p/cgi-bin/drupal/system/files/lectures/1… · •Ideally written along with new code •Test-driven development Write tests first Fill

“How do I launch my app in landscape orientation?”

45Monday, March 15, 2010

Page 91: CS193P - Lecture 18web.stanford.edu/class/cs193p/cgi-bin/drupal/system/files/lectures/1… · •Ideally written along with new code •Test-driven development Write tests first Fill

Launching Your App in Landscape

46Monday, March 15, 2010

Page 92: CS193P - Lecture 18web.stanford.edu/class/cs193p/cgi-bin/drupal/system/files/lectures/1… · •Ideally written along with new code •Test-driven development Write tests first Fill

Launching Your App in Landscape• Two steps

46Monday, March 15, 2010

Page 93: CS193P - Lecture 18web.stanford.edu/class/cs193p/cgi-bin/drupal/system/files/lectures/1… · •Ideally written along with new code •Test-driven development Write tests first Fill

Launching Your App in Landscape• Two steps

■ Specify initial interface orientation in your Info.plist

46Monday, March 15, 2010

Page 94: CS193P - Lecture 18web.stanford.edu/class/cs193p/cgi-bin/drupal/system/files/lectures/1… · •Ideally written along with new code •Test-driven development Write tests first Fill

Launching Your App in Landscape• Two steps

■ Specify initial interface orientation in your Info.plist

■ Support the specified orientation in your view controller

46Monday, March 15, 2010

Page 95: CS193P - Lecture 18web.stanford.edu/class/cs193p/cgi-bin/drupal/system/files/lectures/1… · •Ideally written along with new code •Test-driven development Write tests first Fill

Launching Your App in Landscape• Two steps

■ Specify initial interface orientation in your Info.plist

■ Support the specified orientation in your view controller■ Override -shouldAutorotateToInterfaceOrientation:

46Monday, March 15, 2010

Page 96: CS193P - Lecture 18web.stanford.edu/class/cs193p/cgi-bin/drupal/system/files/lectures/1… · •Ideally written along with new code •Test-driven development Write tests first Fill

Launching Your App in Landscape• Two steps

■ Specify initial interface orientation in your Info.plist

■ Support the specified orientation in your view controller■ Override -shouldAutorotateToInterfaceOrientation:■ Return YES to indicate interface orientations that you support

46Monday, March 15, 2010

Page 97: CS193P - Lecture 18web.stanford.edu/class/cs193p/cgi-bin/drupal/system/files/lectures/1… · •Ideally written along with new code •Test-driven development Write tests first Fill

Launching Your App in Landscape• Two steps

■ Specify initial interface orientation in your Info.plist

■ Support the specified orientation in your view controller■ Override -shouldAutorotateToInterfaceOrientation:■ Return YES to indicate interface orientations that you support

• Works on iPhone OS 2.1 or later

46Monday, March 15, 2010

Page 98: CS193P - Lecture 18web.stanford.edu/class/cs193p/cgi-bin/drupal/system/files/lectures/1… · •Ideally written along with new code •Test-driven development Write tests first Fill

47Monday, March 15, 2010

Page 99: CS193P - Lecture 18web.stanford.edu/class/cs193p/cgi-bin/drupal/system/files/lectures/1… · •Ideally written along with new code •Test-driven development Write tests first Fill

Demo:Launching in Landscape

48Monday, March 15, 2010

Page 100: CS193P - Lecture 18web.stanford.edu/class/cs193p/cgi-bin/drupal/system/files/lectures/1… · •Ideally written along with new code •Test-driven development Write tests first Fill

“How can I customize UIKit views and controls?”

49Monday, March 15, 2010

Page 101: CS193P - Lecture 18web.stanford.edu/class/cs193p/cgi-bin/drupal/system/files/lectures/1… · •Ideally written along with new code •Test-driven development Write tests first Fill

Customizing UIKit Views

50Monday, March 15, 2010

Page 102: CS193P - Lecture 18web.stanford.edu/class/cs193p/cgi-bin/drupal/system/files/lectures/1… · •Ideally written along with new code •Test-driven development Write tests first Fill

Customizing UIKit Views• Some classes are designed to be totally customizable

■ UIButton■ UITableView

50Monday, March 15, 2010

Page 103: CS193P - Lecture 18web.stanford.edu/class/cs193p/cgi-bin/drupal/system/files/lectures/1… · •Ideally written along with new code •Test-driven development Write tests first Fill

Customizing UIKit Views• Some classes are designed to be totally customizable

■ UIButton■ UITableView

• Many classes have limited customizability■ UINavigationBar■ UISlider

50Monday, March 15, 2010

Page 104: CS193P - Lecture 18web.stanford.edu/class/cs193p/cgi-bin/drupal/system/files/lectures/1… · •Ideally written along with new code •Test-driven development Write tests first Fill

Customizing UIKit Views• Some classes are designed to be totally customizable

■ UIButton■ UITableView

• Many classes have limited customizability■ UINavigationBar■ UISlider

• Other classes are not customizable■ UISwitch■ UITabBar

50Monday, March 15, 2010

Page 105: CS193P - Lecture 18web.stanford.edu/class/cs193p/cgi-bin/drupal/system/files/lectures/1… · •Ideally written along with new code •Test-driven development Write tests first Fill

What’s Safe to Customize?• Look for methods for customizing appearance

■ UIButton: background image■ UINavigationBar: style, tint, translucency■ UITableView: delegate methods for appearance

• You can always create your own UIView or UIControl subclass■ Handle touches■ Custom drawing

51Monday, March 15, 2010

Page 106: CS193P - Lecture 18web.stanford.edu/class/cs193p/cgi-bin/drupal/system/files/lectures/1… · •Ideally written along with new code •Test-driven development Write tests first Fill

Respecting the View Hierarchy• Internal view hierarchies are always subject to change

■ Navigation bar■ Navigation and tab bar controllers■ Image picker controller

• Making assumptions is unsafe and will likely break your app■ Don’t manipulate undocumented subviews of system views■ Don’t add your own custom subviews

• You want your application to be future-ready

52Monday, March 15, 2010

Page 107: CS193P - Lecture 18web.stanford.edu/class/cs193p/cgi-bin/drupal/system/files/lectures/1… · •Ideally written along with new code •Test-driven development Write tests first Fill

“Should I create my views using Interface Builder or in code?”

53Monday, March 15, 2010

Page 108: CS193P - Lecture 18web.stanford.edu/class/cs193p/cgi-bin/drupal/system/files/lectures/1… · •Ideally written along with new code •Test-driven development Write tests first Fill

When to Use Interface Builder• Almost always recommended• Especially useful when creating a view with many subviews• Not as useful when dealing with just a single view

■ Table views

• Remember: one view controller subclass, one NIB■ Make connections to view controller via File’s Owner

54Monday, March 15, 2010

Page 109: CS193P - Lecture 18web.stanford.edu/class/cs193p/cgi-bin/drupal/system/files/lectures/1… · •Ideally written along with new code •Test-driven development Write tests first Fill

Nibs and Memory Management

55Monday, March 15, 2010

Page 110: CS193P - Lecture 18web.stanford.edu/class/cs193p/cgi-bin/drupal/system/files/lectures/1… · •Ideally written along with new code •Test-driven development Write tests first Fill

Nibs and Memory Management• Top-level nib objects are autoreleased

■ Retain them if they should stick around after loading

55Monday, March 15, 2010

Page 111: CS193P - Lecture 18web.stanford.edu/class/cs193p/cgi-bin/drupal/system/files/lectures/1… · •Ideally written along with new code •Test-driven development Write tests first Fill

Nibs and Memory Management• Top-level nib objects are autoreleased

■ Retain them if they should stick around after loading

55Monday, March 15, 2010

Page 112: CS193P - Lecture 18web.stanford.edu/class/cs193p/cgi-bin/drupal/system/files/lectures/1… · •Ideally written along with new code •Test-driven development Write tests first Fill

Nibs and Memory Management• Top-level nib objects are autoreleased

■ Retain them if they should stick around after loading

55Monday, March 15, 2010

Page 113: CS193P - Lecture 18web.stanford.edu/class/cs193p/cgi-bin/drupal/system/files/lectures/1… · •Ideally written along with new code •Test-driven development Write tests first Fill

Nibs and Memory Management• Top-level nib objects are autoreleased

■ Retain them if they should stick around after loading

• IBOutlets are retained by default■ Release them in -dealloc even if you don’t have a setter!■ Implement or synthesize a non-retained setter if desired

55Monday, March 15, 2010

Page 114: CS193P - Lecture 18web.stanford.edu/class/cs193p/cgi-bin/drupal/system/files/lectures/1… · •Ideally written along with new code •Test-driven development Write tests first Fill

“Where can I get cool icons for my toolbar or tab bar items?”

56Monday, March 15, 2010

Page 115: CS193P - Lecture 18web.stanford.edu/class/cs193p/cgi-bin/drupal/system/files/lectures/1… · •Ideally written along with new code •Test-driven development Write tests first Fill

Toolbar and Tab Bar Images• Images should be about 30 x 30 pixels• PNG with alpha channel• Used as a mask by UIKit for drawing with system colors

57Monday, March 15, 2010

Page 116: CS193P - Lecture 18web.stanford.edu/class/cs193p/cgi-bin/drupal/system/files/lectures/1… · •Ideally written along with new code •Test-driven development Write tests first Fill

• Glyphish, by Joseph Wain: http://www.glyphish.com• Creative Commons License

■ *Free to use, share, or remix with attribution

Some Great Free* Icons

58Monday, March 15, 2010

Page 117: CS193P - Lecture 18web.stanford.edu/class/cs193p/cgi-bin/drupal/system/files/lectures/1… · •Ideally written along with new code •Test-driven development Write tests first Fill

• Glyphish, by Joseph Wain: http://www.glyphish.com• Creative Commons License

■ *Free to use, share, or remix with attribution

Some Great Free* Icons

58Monday, March 15, 2010

Page 118: CS193P - Lecture 18web.stanford.edu/class/cs193p/cgi-bin/drupal/system/files/lectures/1… · •Ideally written along with new code •Test-driven development Write tests first Fill

“Can I build Mac apps now that I know iPhone development?”

59Monday, March 15, 2010

Page 119: CS193P - Lecture 18web.stanford.edu/class/cs193p/cgi-bin/drupal/system/files/lectures/1… · •Ideally written along with new code •Test-driven development Write tests first Fill

Building iPhone & Mac OS X Apps

60Monday, March 15, 2010

Page 120: CS193P - Lecture 18web.stanford.edu/class/cs193p/cgi-bin/drupal/system/files/lectures/1… · •Ideally written along with new code •Test-driven development Write tests first Fill

Building iPhone & Mac OS X Apps• At this point, you’re familiar with

■ Objective-C language■ Cocoa Touch frameworks■ Object-oriented design patterns■ Interface Builder and NIBs

60Monday, March 15, 2010

Page 121: CS193P - Lecture 18web.stanford.edu/class/cs193p/cgi-bin/drupal/system/files/lectures/1… · •Ideally written along with new code •Test-driven development Write tests first Fill

Building iPhone & Mac OS X Apps• At this point, you’re familiar with

■ Objective-C language■ Cocoa Touch frameworks■ Object-oriented design patterns■ Interface Builder and NIBs

• Developing for the Mac desktop is within your reach!■ First few lectures of CS193P and CS193E are identical

60Monday, March 15, 2010

Page 122: CS193P - Lecture 18web.stanford.edu/class/cs193p/cgi-bin/drupal/system/files/lectures/1… · •Ideally written along with new code •Test-driven development Write tests first Fill

Building iPhone & Mac OS X Apps• At this point, you’re familiar with

■ Objective-C language■ Cocoa Touch frameworks■ Object-oriented design patterns■ Interface Builder and NIBs

• Developing for the Mac desktop is within your reach!■ First few lectures of CS193P and CS193E are identical

• Big difference is Cocoa vs. Cocoa Touch■ Many UIKit and AppKit classes are similar

60Monday, March 15, 2010