iOS 8 was somewhat overshadowed by the introduction of a massive white bird in an orange sky. There were loads of cool new things in iOS 8, and this talk is a walk through some of the more obscure of these.
today • Fixing the things that broke • Alerts / ActionSheets • Popovers • Notifications • CoreLocation • Playing with the unloved shiny things • AVKit • Notification actions • Rotation • Testing
notifications Local No further authorisation required Remote func registerForRemoteNotifications() UIUserNotification Represents the appearance of all notifications (badge / alert / sound) func registerUserNotificationSettings(notificationSettings: UIUserNotificationSettings)
popovers UIPopoverController init(contentViewController viewController: UIViewController) •Not adaptive •Presentation is now handled by UIPresentationController
popovers UIModalPresentationStyle enum UIModalPresentationStyle : Int { case Popover ... } UIViewController var modalPresentationStyle: UIModalPresentationStyle var popoverPresentationController: UIPopoverPresentationController? { get }
popovers UIPopoverPresentationController class UIPopoverPresentationController : UIPresentationController { unowned(unsafe) var delegate: UIPopoverPresentationControllerDelegate? var permittedArrowDirections: UIPopoverArrowDirection var sourceView: UIView! var sourceRect: CGRect var barButtonItem: UIBarButtonItem! var passthroughViews: [AnyObject]! ... }
core location Always • Foreground and background • Able to launch the app • Geofencing / Region monitoring • Even if killed by user • Users will be asked to confim “later” WhenInUse • Foreground only • Not allowed access to launch APIs • Banner displayed when app moves to background •
core location CLLocationManager /* * requestWhenInUseAuthorization * * Discussion: * When +authorizationStatus == kCLAuthorizationStatusNotDetermined, * calling this method will trigger a prompt to request "when-in-use" * authorization from the user. If possible, perform this call in response * to direct user request for a location-based service so that the reason * for the prompt will be clear. Any authorization change as a result of * the prompt will be reflected via the usual delegate callback: * -locationManager:didChangeAuthorizationStatus:. * * If received, "when-in-use" authorization grants access to the user's * location via -startUpdatingLocation/-startRangingBeaconsInRegion while * in the foreground. If updates have been started when going to the * background, then a status bar banner will be displayed to maintain * visibility to the user, and updates will continue until stopped * normally, or the app is killed by the user. * * "When-in-use" authorization does NOT enable monitoring API on regions, * significant location changes, or visits, and -startUpdatingLocation will * not succeed if invoked from the background. * * When +authorizationStatus != kCLAuthorizationStatusNotDetermined, (ie * generally after the first call) this method will do nothing. * * If the NSLocationWhenInUseUsageDescription key is not specified in your * Info.plist, this method will do nothing, as your app will be assumed not * to support WhenInUse authorization. */ @availability(iOS, introduced=8.0) func requestWhenInUseAuthorization()
core location CLLocationManager /* * requestWhenInUseAuthorization * * Discussion: * When +authorizationStatus == kCLAuthorizationStatusNotDetermined, * calling this method will trigger a prompt to request "when-in-use" * authorization from the user. If possible, perform this call in response * to direct user request for a location-based service so that the reason * for the prompt will be clear. Any authorization change as a result of * the prompt will be reflected via the usual delegate callback: * -locationManager:didChangeAuthorizationStatus:. * * If received, "when-in-use" authorization grants access to the user's * location via -startUpdatingLocation/-startRangingBeaconsInRegion while * in the foreground. If updates have been started when going to the * background, then a status bar banner will be displayed to maintain * visibility to the user, and updates will continue until stopped * normally, or the app is killed by the user. * * "When-in-use" authorization does NOT enable monitoring API on regions, * significant location changes, or visits, and -startUpdatingLocation will * not succeed if invoked from the background. * * When +authorizationStatus != kCLAuthorizationStatusNotDetermined, (ie * generally after the first call) this method will do nothing. * * If the NSLocationWhenInUseUsageDescription key is not specified in your * Info.plist, this method will do nothing, as your app will be assumed not * to support WhenInUse authorization. */ @availability(iOS, introduced=8.0) func requestWhenInUseAuthorization()
core location CLLocationManager * If the NSLocationWhenInUseUsageDescription key is not * specified in your Info.plist, this method will do nothing, * as your app will be assumed not to support WhenInUse * authorization. */ @availability(iOS, introduced=8.0) func requestWhenInUseAuthorization()
AVKit AVPlayerViewController class AVPlayerViewController : UIViewController { var player: AVPlayer! var showsPlaybackControls: Bool var videoGravity: String! ... }
notification actions UIUserNotificationAction class UIUserNotificationAction : NSObject, NSCopying, NSMutableCopying, NSSecureCoding, NSCoding { var identifier: String! { get } var title: String! { get } var activationMode: UIUserNotificationActivationMode { get } var authenticationRequired: Bool { get } var destructive: Bool { get } }
notification actions UIMutableUserNotificationAction class UIMutableUserNotificationAction : UIUserNotificationAction { var identifier: String! var title: String! var activationMode: UIUserNotificationActivationMode var authenticationRequired: Bool var destructive: Bool }
async testing func testBasicAsyncMethod() { // Check that we get called back as expected let expectation = expectationWithDescription("Async Method") raceController.someKindOfAsyncMethod({ expectation.fulfill() }) waitForExpectationsWithTimeout(5, handler: nil) }
async testing raceController.startRace(5, horseCrossedLineCallback:{ (horse:Horse) in // Deal with the number of horses self.numberOfHorsesCurrentlyRunning -= 1 if self.numberOfHorsesCurrentlyRunning == 0 { self.resetButton.enabled = true }
async testing func testResetButtonEnabledOnceRaceComplete() { let expectation = keyValueObservingExpectationForObject( viewController.resetButton, keyPath: “enabled", expectedValue: true) // Simulate tapping the start race button viewController.handleStartRaceButton(viewController.startRaceButton) // Wait for the test to run waitForExpectationsWithTimeout(5, handler: nil) }
test performance func testMovingAveragePerformance() { // This is an example of a performance test case. calculator.windowSize = 1000 self.measureBlock() { // Put the code you want to measure the time of here. let randomArray = self.RandomDouble(10000) let result = self.calculator.calculateMovingAverage(randomArray) XCTAssertEqual(result.count, 9000) } }
where next? Custom fonts in Interface Builder Designated initialisers in Swift / ObjC Nullability annotations in ObjC New detectors in CoreImage NSFormatter Auto hiding of navigation/tab bars Custom CIFilter Kernels Live rendering in Interface Builder Layout margins CoreMotion Location notifications NSCalendar additions