那些開發者應該知道但又略顯模糊的iOS 8 API
無論你問任何人,他們都會告訴你:WWDC2014是他們近些時日最令人興奮的一件事,沒有硬件發布信息,完全是關于軟件和開發者工具的。
2014年iOS 8和OS X Yosemite的公布將會讓蘋果平臺成為今年***領導力的平臺, iOS的擴展性,連續性,SpriteKit增強以及SceneKit,還有Metal,Game HealthKit,HomeKit,Local Authentication和全新的拍照框架。更不用說引人注目的Xcode和Interface Builder,改進后的iTunes Connect、TestFlight、Crash Reports以及CloudKit,當然還有Swift!
還要抱怨嗎? 蘋果已經慷慨地放寬了對新技術的保密措施,這意味著我們現在就可以討論那些閃亮的新東西。
本周,我們將探討下以下列出的功能,分享一些iOS 8中每個人都應該知道的但比較模糊的API。
從現在起,NSHipster將主要使用Swift編寫示例代碼,當然偶爾會用Objective-C編寫。夏天結束的時候,我們希望所有的現有代碼樣本都能移植到Swift上,從而在語言間進行迅速切換。
## NSProcessInfo -isOperatingSystemAtLeastVersion ##
忘了[[UIDevice currentDevice] systemVersion] 和NSFoundationVersionNumber吧,這里有一個新的方法可在代碼中確定當前的操作系統:NSProcessInfo -isOperatingSystemAtLeastVersion
- import Foundation
- let yosemite = NSOperatingSystemVersion(majorVersion: 10, minorVersion: 10, patchVersion: 0)
- NSProcessInfo().isOperatingSystemAtLeastVersion(yosemite) // false
不過請記住,為了測試(進行兼容性測試的時候),SomeClass.class或respondsToSelector:是檢查操作系統版本的一個更不錯的選擇。C和Swift編譯器的宏可以
用來有條件地編譯基于目標配置的源。(基于target的構建配置,C或者Swift編譯的宏可以有條件地編譯源代碼)
## 新 NSFormatter 子類 ##
Foundation框架中最為嚴重缺乏就是對數量單位例如質量和長度的處理能力。iOS中8和OS X Yosemite引入了三個新的類--NSEnergyFormatter、NSMassFormatter以及NSLengthFormatter,填 補了這一缺失。這有效地使Foundation框架中NSFormatter子類的數目加倍,以前僅限于NSNumberFormatter、NSDateFormatter以及NSByteCountFormatter。
雖然這些新的格式化類是Foundation框架中的一部分,但是它們主要在HealthKit中使用。
## NSEnergyFormatter ##
NSEnergyFormatter以焦耳和卡路里作為格式化能量單位,焦耳是運動鍛煉時用到的單位,卡路里營養學上熱量單位。
- let energyFormatter = NSEnergyFormatter()
- energyFormatter.forFoodEnergyUse = true
- let joules = 10_000.0
- println(energyFormatter.stringFromJoules(joules)) // "2.39 Cal"
## NSMassFormatter ##
雖然是物質存在的基本單位,但mass在HealthKit中主要指用戶的重量。但還有一句忘記翻譯:是的,Mass和weight是不一樣的,但是在程序中,這里不是科學課程,所以不要那么迂腐了!)
- let massFormatter = NSMassFormatter()
- let kilograms = 60.0
- println(massFormatter.stringFromKilograms(kilograms)) // "132 lb"
## NSLengthFormatter ##
為完善新NSFormatter,還有一個子類是NSLengthFormatter。把它看成是一個MKDistanceFormatter的更有用版本,它擁有更多的單位選項和格式設置選項。
- let lengthFormatter = NSLengthFormatter()
- let meters = 5_000.0
- println(lengthFormatter.stringFromMeters(meters)) // "3.107 mi"
## CMPedometer ##
iOS 8繼續了之前的健康路線,在最近一次發布中,CMStepCounter比之前做了嚴格的改進,可及時從離散數據點進行查詢,跟蹤用戶的步數和距離,甚至計算用戶爬了多少級樓梯。
令人驚訝的是M7的芯片可以勝任這項任務。
- import CoreMotion
- let lengthFormatter = NSLengthFormatter()
- let pedometer = CMPedometer()
- pedometer.startPedometerUpdatesFromDate(NSDate(), withHandler: { data, error in
- if !error {
- println("Steps Taken: \(data.numberOfSteps)")
- let distance = data.distance.doubleValue
- println("Distance: \(lengthFormatter.stringFromMeters(distance))")
- let time = data.endDate.timeIntervalSinceDate(data.startDate)
- let speed = distance / time
- println("Speed: \(lengthFormatter.stringFromMeters(speed)) / s")
- }
- })
## CMAltimeter ##
在支持的設備上,CMPedometer對floorsAscended/ floorsDescended的統計可使用CMAltimeter進行擴充,以獲得更精細的垂直距離:
- import CoreMotion
- let altimeter = CMAltimeter()
- if CMAltimeter.isRelativeAltitudeAvailable() {
- altimeter.startRelativeAltitudeUpdatesToQueue(NSOperationQueue.mainQueue(), withHandler: { data, error in
- if !error {
- println("Relative Altitude: \(data.relativeAltitude)")
- }
- })
- }
## CLFloor ##
CLFloor是iOS 8中的新API,CoreMotion中的新功能體現了蘋果公司的雄心勃勃的室內導航計劃。這些信息將會在本地化導航應用中扮演重要的角色。
- import CoreLocation
- class LocationManagerDelegate: NSObject, CLLocationManagerDelegate {
- func locationManager(manager: CLLocationManager!, didUpdateLocations locations: AnyObject[]!) {
- let location: CLLocation? = locations[0] as? CLLocation
- if let floor: CLFloor? = location?.floor {
- println("Current Floor: \(floor?.level)")
- }
- }
- }
- let manager = CLLocationManager()
- manager.delegate = LocationManagerDelegate()
- manager.startUpdatingLocation()
## HKStatistics ##
作為一個框架,HealthKit涉及了很廣泛的范圍,包括許多個新的類和常量。理解HKStatistics存在的可能性給了開發者一個良好的開端。
HealthKit在一個統一的API中管理著來自用戶所有設備中的生物數據,可以用強大的方式跟蹤并匯總用戶的多項生物數據,比如心率、熱量攝入以及有氧輸出等數據。
下面示例展示了如何對持續一天的數據進行分組和逐個解讀:
- import HealthKit
- let collection: HKStatisticsCollection? = ...
- let statistics: HKStatistics? = collection!.statisticsForDate(NSDate())
- for item: AnyObject in statistics!.sources {
- if let source = item as? HKSource {
- if let quantity: HKQuantity = statistics!.sumQuantityForSource(source) {
- if quantity.isCompatibleWithUnit(HKUnit.gramUnitWithMetricPrefix(.Kilo)) {
- let massFormatter = NSMassFormatter()
- let kilograms = quantity.doubleValueForUnit(HKUnit.gramUnitWithMetricPrefix(.Kilo))
- println(massFormatter.stringFromKilograms(kilograms))
- }
- if quantity.isCompatibleWithUnit(HKUnit.meterUnit()) {
- let lengthFormatter = NSLengthFormatter()
- let meters = quantity.doubleValueForUnit(HKUnit.meterUnit())
- println(lengthFormatter.stringFromMeters(meters))
- }
- if quantity.isCompatibleWithUnit(HKUnit.jouleUnit()) {
- let energyFormatter = NSEnergyFormatter()
- let joules = quantity.doubleValueForUnit(HKUnit.jouleUnit())
- println(energyFormatter.stringFromJoules(joules))
- }
- }
- }
- }
NSHipster后期將涵蓋更多有關HealthKit的功能,敬請期待!
## NSStream +getStreamsToHostWithName ##
從很多方面看,WWDC 2014上蘋果修補了此前存在的諸多不足之處。一些很小的事情,比如添加缺失的NSStream initializer,而不是依賴笨拙橋接CFStreamCreatePairWithSocketToHost的調用。這就是+[NSStream getStreamsToHostWithName:port:inputStream:outputStream:]
- var inputStream: NSInputStream?
- var outputStream: NSOutputStream?
- NSStream.getStreamsToHostWithName(hostname: "nshipster.com",
- port: 5432,
- inputStream: &inputStream,
- outputStream: &outputStream)
## NSString -localizedCaseInsensitiveContainsString ##
又如下面這個是“小而堅實的修復”,一種更簡便的NSString的方法:
- let string: NSString = "Café"
- let substring: NSString = "É"
- string.localizedCaseInsensitiveContainsString(substring) // true
## CTRubyAnotationRef ##
如果你是一個語言學和文字排版的執著者,那么CoreText框架新增添的部分可能會令你起身歡呼了。
......哦對。不過這個Ruby不是你印象中的Ruby,它用來在某些亞洲人的腳本中展示字符發音的。
- @import CoreText;
- NSString *kanji = @"貓";
- NSString *hiragana = @"ねこ";
- CFStringRef furigana[kCTRubyPositionCount] =
- {(__bridge CFStringRef)hiragana, NULL, NULL, NULL};
- CTRubyAnnotationRef ruby =
- CTRubyAnnotationCreate(kCTRubyAlignmentAuto, kCTRubyOverhangAuto, 0.5, furigana);
不可否認,文檔沒有完全清晰地描述如何精確地將這部分合并到剩余的CoreText繪制調用中,但是結果看起來也許會是這樣:
ねこ
貓
## 新的日歷識別符 ##
有什么比Ruby注釋更書***氣的?iOS 8和OS X Yosemite中添加了新日歷標識符。此次更新讓Foundation框架更新至***的CLDR版本。不過,在NSHipsters看來,French Republican Calendar(法國共和歷)依然有自己的亮點。
新日歷識別符:
- NSCalendarIdentifierCoptic: 又名亞歷山大歷,之前被Coptic Orthodox Church使用。
- NSCalendarIdentifierEthiopicAmeteMihret:埃塞俄比亞日歷,Amete Mihret(公元8世紀左右)
- NSCalendarIdentifierEthiopicAmeteAlem:埃塞俄比亞日歷,Amete Alem(公元前5493前后)
- NSCalendarIdentifierIslamicTabular:一個簡單的伊斯蘭歷法表格,在公元622年7月15日星期四的天文時代使用。
- NSCalendarIdentifierIslamicUmmAlQura:在沙特阿拉伯使用的伊斯蘭烏姆Qura日歷。根據天文計算,而不是表格的行為。
#p#
## NSURLCredentialStorage ##
自去年引入NSURLSession后,Foundation的URL載入系統基本上沒有太大變化。但是,這個新功能可讓你更方便地以異步非閉包的形式獲取和設置任務憑證。
- import Foundation
- let session = NSURLSession()
- let task = session.dataTaskWithURL(NSURL(string: "http://nshipster.com"), completionHandler: { data, response, error in
- // ...
- })
- let protectionSpace = NSURLProtectionSpace()
- NSURLCredentialStorage.getCredentialsForProtectionSpace(protectionSpace: protectionSpace, task: task, completionHandler: { credentials in
- // ...
- })
## kUTTypeToDoItem ##
對比過***的API后,人們可能會注意到大量新的UTIs常量,最吸引我的是kUTTypeToDoItem:
- import MobileCoreServices
- kUTTypeToDoItem // "public.to-do-item"
作為一個公眾類型,現在iOS和OS X提供了一個統一的方法來共享應用程序之間的任務。如果你碰巧正在開發一個任務管理工具,那么適當地整合這個系統類型應該是你首先要做的工作。(說實話,機會是非常好的,考慮在App Store有多少這樣的工具)
## kCGImageMetadataShouldExcludeGPS ##
大多數用戶都完全不知道用手機拍攝的大部分照片,包含了全球定位系統(GPS)的元數據。因為這個小細節,無數個人的隱私遭受侵犯。***的圖片 I/O框架又為CGImageDestination提供一個方便的新選項:kCGImageMetadataShouldExcludeGPS,這確實 是你所期望的東西。
- @import UIKit;
- @import ImageIO;
- @import MobileCoreServices;
- UIImage *image = ...;
- NSURL *fileURL = [NSURL fileURLWithPath:@"/path/to/output.jpg"];
- NSString *UTI = kUTTypeJPEG;
- NSDictionary *options = @{
- (__bridge id)kCGImageDestinationLossyCompressionQuality: @(0.75),
- (__bridge id)kCGImageMetadataShouldExcludeGPS: @(YES),
- };
- CGImageDestinationRef imageDestinationRef =
- CGImageDestinationCreateWithURL((__bridge CFURLRef)fileURL,
- (__bridge CFStringRef)UTI,
- 1,
- NULL);
- CGImageDestinationAddImage(imageDestinationRef, [image CGImage], (__bridge CFDictionaryRef)options);
- CGImageDestinationFinalize(imageDestinationRef);
- CFRelease(imageDestinationRef);
## WTF_PLATFORM_IOS ##
#define WTF_PLATFORM_IOS`已經從`JavaScriptCore`中移除了。
## WKWebView ##
UIWebView已死,WKWebView長存。
WKWebView為你自己的應用程序提供Safari瀏覽器級別的性能,并進一步提高了UIWebView的使用偏好和配置:
- import WebKit
- let preferences = WKPreferences()
- preferences.javaScriptCanOpenWindowsAutomatically = false
- let configuration = WKWebViewConfiguration()
- configuration.preferences = preferences
- let webView = WKWebView(frame: self.view.bounds, configuration: configuration)
- let request = NSURLRequest(URL: NSURL(string: "http://nshipster.com"))
- webView.loadRequest(request)
## NSQualityOfService ##
蘋果框架概念基礎中將不再過分強調線程這個概念。這對開發者確實一件好事。
以下這種趨勢的變化在***的API也應用于NSOperation。新的qualityOfService屬性替換了ThreadPriority。這些新的語義允許應用程序推遲非關鍵工作,以確保始終如一的用戶體驗。
該NSQualityOfService枚舉定義了以下值:
- UserInteractive:在實現圖形密集型相關工作時使用UserInteractive QoS,比如滾動或動畫。
- UserInitiated:在實現用戶精確請求請求相關工作時使用UserInitiated QoS,但不要求精確到毫秒,比如動畫。例如,如果用戶打開email app馬上查看郵件。
- Utility:Utility QoS用于執行已經由用戶請求自動發生的任務。例如,電子郵件應用程序可以被配置為每隔5分鐘自動檢查郵件。如果系統是非常有限的資源,而電子郵件檢查被推遲幾分鐘這也是被允許的。
- Background: Background QoS用于執行用戶可能甚至都沒有意識到正在發生的工作,比如email app可能使用它來執行索引搜索。
Quality of Service貫穿了IOS 8和OS X Yosemite整個Foundation,所以好好利用這一新功能吧。
## LocalAuthentication ##
***,一個iOS 8最值得期待的功能:LocalAuthentication。自從iPhone5S引入TouchID之后,開發人員一直樂此不疲的在自己的應用程序中進行使用。
想象一下:有了CloudKit和LocalAuthentication,創建用戶帳戶的障礙已經一去不復返了。只需掃描一下你的指紋,你就能進入了。
LocalAuthentication以LAContext類的方式工作,評估一個特定的策略,并給出一個拇指朝上或者朝下的用戶驗證。它不會將用戶的信息提供給應用程序,所有數據都被保存在硬件中。
- LAContext *context = [[LAContext alloc] init];
- NSError *error = nil;
- if ([context canEvaluatePolicy:LAPolicyDeviceOwnerAuthenticationWithBiometrics
- error:&error])
- {
- [context evaluatePolicy:LAPolicyDeviceOwnerAuthenticationWithBiometrics
- localizedReason:NSLocalizedString(@"...", nil)
- reply:^(BOOL success, NSError *error) {
- if (success) {
- // ...
- } else {
- NSLog(@"%@", error);
- }
- }];
- } else {
- NSLog(@"%@", error);
- }
結語
雖然這些天看起來像所有人在談論Swift,但如果我們忽略了iOS 8 & OS X Yosemite中這些新的API,那就有點遺憾了,它們可以為你做些實際的事情.