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.
© Copyright 2024