那些開發(fā)者應(yīng)該知道但又略顯模糊的iOS 8 API
無論你問任何人,他們都會告訴你:WWDC2014是他們近些時日最令人興奮的一件事,沒有硬件發(fā)布信息,完全是關(guān)于軟件和開發(fā)者工具的。
2014年iOS 8和OS X Yosemite的公布將會讓蘋果平臺成為今年***領(lǐng)導(dǎo)力的平臺, iOS的擴展性,連續(xù)性,SpriteKit增強以及SceneKit,還有Metal,Game HealthKit,HomeKit,Local Authentication和全新的拍照框架。更不用說引人注目的Xcode和Interface Builder,改進后的iTunes Connect、TestFlight、Crash Reports以及CloudKit,當(dāng)然還有Swift!
還要抱怨嗎? 蘋果已經(jīng)慷慨地放寬了對新技術(shù)的保密措施,這意味著我們現(xiàn)在就可以討論那些閃亮的新東西。
本周,我們將探討下以下列出的功能,分享一些iOS 8中每個人都應(yīng)該知道的但比較模糊的API。
從現(xiàn)在起,NSHipster將主要使用Swift編寫示例代碼,當(dāng)然偶爾會用Objective-C編寫。夏天結(jié)束的時候,我們希望所有的現(xiàn)有代碼樣本都能移植到Swift上,從而在語言間進行迅速切換。
## NSProcessInfo -isOperatingSystemAtLeastVersion ##
忘了[[UIDevice currentDevice] systemVersion] 和NSFoundationVersionNumber吧,這里有一個新的方法可在代碼中確定當(dāng)前的操作系統(tǒng):NSProcessInfo -isOperatingSystemAtLeastVersion
- import Foundation
- let yosemite = NSOperatingSystemVersion(majorVersion: 10, minorVersion: 10, patchVersion: 0)
- NSProcessInfo().isOperatingSystemAtLeastVersion(yosemite) // false
不過請記住,為了測試(進行兼容性測試的時候),SomeClass.class或respondsToSelector:是檢查操作系統(tǒng)版本的一個更不錯的選擇。C和Swift編譯器的宏可以
用來有條件地編譯基于目標配置的源。(基于target的構(gòu)建配置,C或者Swift編譯的宏可以有條件地編譯源代碼)
## 新 NSFormatter 子類 ##
Foundation框架中最為嚴重缺乏就是對數(shù)量單位例如質(zhì)量和長度的處理能力。iOS中8和OS X Yosemite引入了三個新的類--NSEnergyFormatter、NSMassFormatter以及NSLengthFormatter,填 補了這一缺失。這有效地使Foundation框架中NSFormatter子類的數(shù)目加倍,以前僅限于NSNumberFormatter、NSDateFormatter以及NSByteCountFormatter。
雖然這些新的格式化類是Foundation框架中的一部分,但是它們主要在HealthKit中使用。
## NSEnergyFormatter ##
NSEnergyFormatter以焦耳和卡路里作為格式化能量單位,焦耳是運動鍛煉時用到的單位,卡路里營養(yǎng)學(xué)上熱量單位。
- let energyFormatter = NSEnergyFormatter()
- energyFormatter.forFoodEnergyUse = true
- let joules = 10_000.0
- println(energyFormatter.stringFromJoules(joules)) // "2.39 Cal"
## NSMassFormatter ##
雖然是物質(zhì)存在的基本單位,但mass在HealthKit中主要指用戶的重量。但還有一句忘記翻譯:是的,Mass和weight是不一樣的,但是在程序中,這里不是科學(xué)課程,所以不要那么迂腐了?。?/p>
- let massFormatter = NSMassFormatter()
- let kilograms = 60.0
- println(massFormatter.stringFromKilograms(kilograms)) // "132 lb"
## NSLengthFormatter ##
為完善新NSFormatter,還有一個子類是NSLengthFormatter。把它看成是一個MKDistanceFormatter的更有用版本,它擁有更多的單位選項和格式設(shè)置選項。
- let lengthFormatter = NSLengthFormatter()
- let meters = 5_000.0
- println(lengthFormatter.stringFromMeters(meters)) // "3.107 mi"
## CMPedometer ##
iOS 8繼續(xù)了之前的健康路線,在最近一次發(fā)布中,CMStepCounter比之前做了嚴格的改進,可及時從離散數(shù)據(jù)點進行查詢,跟蹤用戶的步數(shù)和距離,甚至計算用戶爬了多少級樓梯。
令人驚訝的是M7的芯片可以勝任這項任務(wù)。
- 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 ##
在支持的設(shè)備上,CMPedometer對floorsAscended/ floorsDescended的統(tǒng)計可使用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中的新功能體現(xiàn)了蘋果公司的雄心勃勃的室內(nèi)導(dǎo)航計劃。這些信息將會在本地化導(dǎo)航應(yīng)用中扮演重要的角色。
- 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存在的可能性給了開發(fā)者一個良好的開端。
HealthKit在一個統(tǒng)一的API中管理著來自用戶所有設(shè)備中的生物數(shù)據(jù),可以用強大的方式跟蹤并匯總用戶的多項生物數(shù)據(jù),比如心率、熱量攝入以及有氧輸出等數(shù)據(jù)。
下面示例展示了如何對持續(xù)一天的數(shù)據(jù)進行分組和逐個解讀:
- 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后期將涵蓋更多有關(guān)HealthKit的功能,敬請期待!
## NSStream +getStreamsToHostWithName ##
從很多方面看,WWDC 2014上蘋果修補了此前存在的諸多不足之處。一些很小的事情,比如添加缺失的NSStream initializer,而不是依賴笨拙橋接CFStreamCreatePairWithSocketToHost的調(diào)用。這就是+[NSStream getStreamsToHostWithName:port:inputStream:outputStream:]
- var inputStream: NSInputStream?
- var outputStream: NSOutputStream?
- NSStream.getStreamsToHostWithName(hostname: "nshipster.com",
- port: 5432,
- inputStream: &inputStream,
- outputStream: &outputStream)
## NSString -localizedCaseInsensitiveContainsString ##
又如下面這個是“小而堅實的修復(fù)”,一種更簡便的NSString的方法:
- let string: NSString = "Café"
- let substring: NSString = "É"
- string.localizedCaseInsensitiveContainsString(substring) // true
## CTRubyAnotationRef ##
如果你是一個語言學(xué)和文字排版的執(zhí)著者,那么CoreText框架新增添的部分可能會令你起身歡呼了。
......哦對。不過這個Ruby不是你印象中的Ruby,它用來在某些亞洲人的腳本中展示字符發(fā)音的。
- @import CoreText;
- NSString *kanji = @"貓";
- NSString *hiragana = @"ねこ";
- CFStringRef furigana[kCTRubyPositionCount] =
- {(__bridge CFStringRef)hiragana, NULL, NULL, NULL};
- CTRubyAnnotationRef ruby =
- CTRubyAnnotationCreate(kCTRubyAlignmentAuto, kCTRubyOverhangAuto, 0.5, furigana);
不可否認,文檔沒有完全清晰地描述如何精確地將這部分合并到剩余的CoreText繪制調(diào)用中,但是結(jié)果看起來也許會是這樣:
ねこ
貓
## 新的日歷識別符 ##
有什么比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日歷。根據(jù)天文計算,而不是表格的行為。
#p#
## NSURLCredentialStorage ##
自去年引入NSURLSession后,F(xiàn)oundation的URL載入系統(tǒng)基本上沒有太大變化。但是,這個新功能可讓你更方便地以異步非閉包的形式獲取和設(shè)置任務(wù)憑證。
- 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"
作為一個公眾類型,現(xiàn)在iOS和OS X提供了一個統(tǒng)一的方法來共享應(yīng)用程序之間的任務(wù)。如果你碰巧正在開發(fā)一個任務(wù)管理工具,那么適當(dāng)?shù)卣线@個系統(tǒng)類型應(yīng)該是你首先要做的工作。(說實話,機會是非常好的,考慮在App Store有多少這樣的工具)
## kCGImageMetadataShouldExcludeGPS ##
大多數(shù)用戶都完全不知道用手機拍攝的大部分照片,包含了全球定位系統(tǒng)(GPS)的元數(shù)據(jù)。因為這個小細節(jié),無數(shù)個人的隱私遭受侵犯。***的圖片 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`已經(jīng)從`JavaScriptCore`中移除了。
## WKWebView ##
UIWebView已死,WKWebView長存。
WKWebView為你自己的應(yīng)用程序提供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 ##
蘋果框架概念基礎(chǔ)中將不再過分強調(diào)線程這個概念。這對開發(fā)者確實一件好事。
以下這種趨勢的變化在***的API也應(yīng)用于NSOperation。新的qualityOfService屬性替換了ThreadPriority。這些新的語義允許應(yīng)用程序推遲非關(guān)鍵工作,以確保始終如一的用戶體驗。
該NSQualityOfService枚舉定義了以下值:
- UserInteractive:在實現(xiàn)圖形密集型相關(guān)工作時使用UserInteractive QoS,比如滾動或動畫。
- UserInitiated:在實現(xiàn)用戶精確請求請求相關(guān)工作時使用UserInitiated QoS,但不要求精確到毫秒,比如動畫。例如,如果用戶打開email app馬上查看郵件。
- Utility:Utility QoS用于執(zhí)行已經(jīng)由用戶請求自動發(fā)生的任務(wù)。例如,電子郵件應(yīng)用程序可以被配置為每隔5分鐘自動檢查郵件。如果系統(tǒng)是非常有限的資源,而電子郵件檢查被推遲幾分鐘這也是被允許的。
- Background: Background QoS用于執(zhí)行用戶可能甚至都沒有意識到正在發(fā)生的工作,比如email app可能使用它來執(zhí)行索引搜索。
Quality of Service貫穿了IOS 8和OS X Yosemite整個Foundation,所以好好利用這一新功能吧。
## LocalAuthentication ##
***,一個iOS 8最值得期待的功能:LocalAuthentication。自從iPhone5S引入TouchID之后,開發(fā)人員一直樂此不疲的在自己的應(yīng)用程序中進行使用。
想象一下:有了CloudKit和LocalAuthentication,創(chuàng)建用戶帳戶的障礙已經(jīng)一去不復(fù)返了。只需掃描一下你的指紋,你就能進入了。
LocalAuthentication以LAContext類的方式工作,評估一個特定的策略,并給出一個拇指朝上或者朝下的用戶驗證。它不會將用戶的信息提供給應(yīng)用程序,所有數(shù)據(jù)都被保存在硬件中。
- 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);
- }
結(jié)語
雖然這些天看起來像所有人在談?wù)揝wift,但如果我們忽略了iOS 8 & OS X Yosemite中這些新的API,那就有點遺憾了,它們可以為你做些實際的事情.