File

Everything Else
CS193W - Lecture 4
Agenda
•
The screen
•
Settings bundles
•
Accessibility
•
The App Store
•
Advice from Other Developers
The Screen
•
OLED (organic light-emitting diode) screen.
•
A black pixel means the pixel is off, i.e. not
consuming power.
Settings
•
Settings are found in the
Apple Watch app on
your iPhone
Adding a Settings Bundle
Go to File -> New -> Target…
Add it to the Containing App
It must be called Settings-Watch.bundle
Tell it Which App Group to
Use
Accessing Settings
NSUserDefaults *defaults = [[NSUserDefaults alloc]
initWithSuiteName:@“group.edu.stanford.cs193p”];
BOOL enabled = [defaults boolForKey:@"enabled_preference"];
WKInterfaceObject
•
The base class for all other interface objects
•
You should not subclass WKInterfaceObject or its
subclasses
Updating
WKInterfaceObjects
•
Updates are coalesced per each update cycle
•
If you change an attribute of a WKInterfaceObject
more than once per cycle, Xcode will print a
warning. Only the final value will be sent over.
Common Methods
•
setHidden:
•
setAlpha:
•
setWidth:
•
setHeight:
•
Use 0.0 for setWidth or setHeight to default to the
storyboard value
Accessibility
•
Apple Watch can speak aloud accessibility labels, hints, and
values
•
Label. A short, localized word or phrase that succinctly
describes the control or view, but does not identify the element’s
type. Examples are “Add” or “Play.”.
•
Hint. A brief, localized phrase that describes the results of an
action on an element. Examples are “Adds a title” or “Opens the
shopping list.”
•
Value. The current value of an element, when the value is not
represented by the label. For example, the label for a slider
might be “Speed,” but its current value might be “50%.”
Accessibility Methods
func setAccessibilityLabel(_ accessibilityLabel: String?)
func setAccessibilityHint(_ accessibilityHint: String?)
func setAccessibilityValue(_ accessibilityValue: String?)
WKAccessibilityImageRegion
func setAccessibilityImageRegions(_ accessibilityImageRegions: [ AnyObject ])
let region1 = WKAccessibilityImageRegion()
region1.frame = CGRect(x: 0, y: 0, width: 30, height: 30)
region1.label = "Clown Face"
let region2 = WKAccessibilityImageRegion()
region2.frame = CGRect(x: 0, y: 30, width: 30, height: 30)
region2.label = "Mini-Golf Set"
todoTable.setAccessibilityImageRegions([ region1, region2 ])
The App Store is Open!
App Pages
Lessons Learned by Other
Developers
•
This section is based on:
•
http://realm.io/news/watchkit-mistakes
Dealing With Latency
•
What happens if this view or action takes a long time to
respond?
•
How will the app react if it doesn’t get a response at all?
•
What can I do to mitigate those problems?
•
Caching
•
Downloading data before the user needs it / background
fetching
•
If the user has to wait, show a delightful loading animation
Image Speed
•
Don’t call WKInterfaceImage:setImage
•
Instead call WKInterfaceImageData: with JPEG or PNG
data
•
For animated images, use UIImage
animatedImageWithImages:duration: and encode it using
NSKeyedArchiver
•
Note that duration is ignored; it is set using
WKInterfaceImage
startAnimatingWithImagesInRange:duration:repeatCount:
Use Groups instead of
Images if Possible
Passing Data in
handleWatchKitExtensionRequest
•
Needs to pass plist-able data (NSNumber, String, Bool, Array, Dictionary, NSDate,
NSData)
•
Can use NSKeyedArchiver to archive other objects to NSData
•
Archiving data:
NSMutableDictionary *reply = [NSMutableDictionary new];
MyCustomObject *myObject = <something you need to send>;
reply[@"myKey"] = [NSKeyedArchiver archivedDataWithRootObject: myObject];
NSAttributedString *myString = <some attributed string>;
reply[@"otherKey"] = [NSKeyedArchiver archivedDataWithRootObject: myString];
•
Unarchiving data:
NSData *objectData = replyInfo[@"myKey"];
MyCustomObject *myObject = [NSKeyedUnarchiver unarchiveObjectWithData: objectData];
NSData *stringData = replyInfo[@"otherKey"];
NSAttributedString *myString = [NSKeyedUnarchiver unarchiveObjectWithData: stringData];
•
Implement initWithCoder: and encodeWithCoder: in your custom classes to make
them work with NSKeyedArchiver
initWithCoder:
@interface Student : NSObject <NSCoding> {
NSString *studentID;
NSString *studentName;
}
@property (copy) NSString *studentID;
@property (copy) NSString *studentName;
+ (Student *)initWithStudentID:(NSString *)ID andStudentName:(NSString *)name;
@end
+ (Student *)initWithStudentID:(NSString *)ID andStudentName:(NSString *)name {
Student *student = [[Student alloc] init];
student.studentID = [NSString stringWithString:ID];
student.studentName = [NSString stringWithString:name];
return [student autorelease];
}
}
(id)initWithCoder:(NSCoder *)aDecoder {
if (self = [super init]) {
[self setStudentID:[aDecoder decodeObjectForKey:@"studentID]];
[self setStudentName:[aDecoder decodeObjectForKey:@"studentName"]];
}
return self;
- (void)encodeWithCoder:(NSCoder *)aCoder {
[aCoder encodeObject:studentID forKey:@"studentID"];
[aCoder encodeObject:studentName forKey:@"studentName"];
}
MMWormhole
•
Uses CFNotificationCenter Darwin Notifications to
support realtime change notifications.