iOS 8
随便去问任何人,他们都会告诉你 WWDC2014 是近年来最为激动的回忆。 整个大会没有发布任何新硬件,它是一次史无前例的软件开发者盛宴!
仅是 iOS 8 和 OS X Yosemite 的发布就能让 2014 成为苹果平台划时代的一年,加上 Extension,Continuity,SpriteKit 改进,iOS SceneKit,Metal,HealthKit,Local Authentication 和全新的照片框架。更不用说,Xcode 和 Interface Builder 的明显改观,重新设计的 iTunes Connect,TestFlight,崩溃报告和 CloudKit。当然还有 oh yeah-Swift。
更棒的是?苹果放松了她的保密协定,也就是说我们可以现在就公开讨论这些崭新的玩具!
这周,我们将拨开 iOS 8 的云雾,探讨一些所有人都应该知道新 API。
从现在开始 NSHipster 将主要使用 Swift 编写样例代码。夏天结束之前,我们希望能将全部的现存代码转换为 Swift,并且提供可以切换语言的选项。
NSProcessInfo -isOperatingSystemAtLeastVersion
忘记[[UIDevice current
和NSFoundation
吧, 现在可以用NSProcess
来确定系统版本。
import Foundation
let yosemite = NSOperating System Version(major Version: 10, minor Version: 10, patch Version: 0)
NSProcess Info().is Operating System At Least Version(yosemite) // false
值得注意的是,在做兼容性测试的时候还是应该使用Some
或responds
。 Swift 和 C 中的编译器宏可以用来根据不同生成配置和目标来选择代码。
新的 NSFormatter 子类
Foundation 中严重缺失的一项功能就是不能处理重量和长度单位转换。在 iOS 8 和 OS X Yosemite 中,引进了三个新类NSEnergy
,NSMass
和NSLength
来弥补这一缺失。
这使得
NSFormatter
子类的数量翻了一倍, 之前只有NSNumber
,Formatter NSDate
和Formatter NSByte
。Count Formatter
虽然这些都是 Foundation 的子类,但是它们主要都是在 HealthKit 当中使用。
NSEnergyFormatter
NSEnergy
使用焦作为能量的原始单位,当处理健康信息时,则使用卡.
let energy Formatter = NSEnergy Formatter()
energy Formatter.for Food Energy Use = true
let joules = 10_000.0
println(energy Formatter.string From Joules(joules)) // "2.39 Cal"
NSMassFormatter
虽然质量是物质存在的基本单位, 在 HealthKit 中,它主要指的是身体重量.
let mass Formatter = NSMass Formatter()
let kilograms = 60.0
println(mass Formatter.string From Kilograms(kilograms)) // "132 lb"
NSLengthFormatter
NSFormatter
的最后一个新子类是NSLength
. 我们可以把它想象为MKDistance
的加强版。
let length Formatter = NSLength Formatter()
let meters = 5_000.0
println(length Formatter.string From Meters(meters)) // "3.107 mi"
CMPedometer
沿着 iOS 8 的健康路线, CMStep
被重新设计了. CMPedometer
作为它的改良版本不仅可以即时获取离散的点数据,并且可以同时跟踪脚步和距离,甚至计算总共爬了多少级楼梯。
M7 芯片真是功能强大.
import Core Motion
let length Formatter = NSLength Formatter()
let pedometer = CMPedometer()
pedometer.start Pedometer Updates From Date(NSDate(), with Handler: { data, error in
if !error {
println("Steps Taken: \(data.number Of Steps)")
let distance = data.distance.double Value
println("Distance: \(length Formatter.string From Meters(distance))")
let time = data.end Date.time Interval Since Date(data.start Date)
let speed = distance / time
println("Speed: \(length Formatter.string From Meters(speed)) / s")
}
})
CMAltimeter
在支持的设备上,CMAltimeter
可以让CMPedometer
的floors
,floors
数据更加精准:
import Core Motion
let altimeter = CMAltimeter()
if CMAltimeter.is Relative Altitude Available() {
altimeter.start Relative Altitude Updates To Queue(NSOperation Queue.main Queue(), with Handler: { data, error in
if !error {
println("Relative Altitude: \(data.relative Altitude)")
}
})
}
CLFloor
CLFloor
的引入展示了苹果进军室内导航的宏伟计划,楼层信息将扮演着重要的角色。
import Core Location
class Location Manager Delegate: NSObject, CLLocation Manager Delegate {
func location Manager(manager: CLLocation Manager!, did Update Locations locations: Any Object[]!) {
let location: CLLocation? = locations[0] as? CLLocation
if let floor: CLFloor? = location?.floor {
println("Current Floor: \(floor?.level)")
}
}
}
let manager = CLLocation Manager()
manager.delegate = Location Manager Delegate()
manager.start Updating Location()
HKStatistics
作为一个框架,HealthKit 包含着大量的子类和常量。要想全部理解,HKStatistics
是一个很好的开始。
HealthKit 管理着所有的生理信息,例如:心率,卡路里摄入量,血氧等等,并且通过统一的 API 聚合在一起。
下面这个例子演示了如何从一天的连续数据中,挖掘和获取单独的数据:
import Health Kit
let collection: HKStatistics Collection? = ...
let statistics: HKStatistics? = collection!.statistics For Date(NSDate())
for item: Any Object in statistics!.sources {
if let source = item as? HKSource {
if let quantity: HKQuantity = statistics!.sum Quantity For Source(source) {
if quantity.is Compatible With Unit(HKUnit.gram Unit With Metric Prefix(.Kilo)) {
let mass Formatter = NSMass Formatter()
let kilograms = quantity.double Value For Unit(HKUnit.gram Unit With Metric Prefix(.Kilo))
println(mass Formatter.string From Kilograms(kilograms))
}
if quantity.is Compatible With Unit(HKUnit.meter Unit()) {
let length Formatter = NSLength Formatter()
let meters = quantity.double Value For Unit(HKUnit.meter Unit())
println(length Formatter.string From Meters(meters))
}
if quantity.is Compatible With Unit(HKUnit.joule Unit()) {
let energy Formatter = NSEnergy Formatter()
let joules = quantity.double Value For Unit(HKUnit.joule Unit())
println(energy Formatter.string From Joules(joules))
}
}
}
}
NSHipster 将会在未来探讨更多的 HealthKit,敬请关注!
NSStream +getStreamsToHostWithName
在许多方面,WWDC 2014 也是苹果查漏补遗的一年,比如给NSStream
添加了新的 initializer(再也不用调用CFStream
了),这就是:+[NSStream get
var input Stream: NSInput Stream?
var output Stream: NSOutput Stream?
NSStream.get Streams To Host With Name(hostname: "nshipster.com",
port: 5432,
input Stream: &input Stream,
output Stream: &output Stream)
NSString -localizedCaseInsensitiveContainsString
这又是一个NSString
小而实用的修缮:
let string: NSString = "Café"
let substring: NSString = "É"
string.localized Case Insensitive Contains String(substring) // true
CTRubyAnnotationRef
好吧,此Ruby非彼Ruby. . 这是用来给亚洲文字添加注音符号的.
@import Core Text;
NSString *kanji = @"猫";
NSString *hiragana = @"ねこ";
CFString Ref furigana[k CTRuby Position Count] =
{(__bridge CFString Ref)hiragana, NULL, NULL, NULL};
CTRuby Annotation Ref ruby =
CTRuby Annotation Create(k CTRuby Alignment Auto, k CTRuby Overhang Auto, 0.5, furigana);
无可否认的是,文档中并没有很清晰的描述具体如何将它整合进入你剩下的Core
中,但是结果如下:
猫
新的日历识别符
iOS 8 和 OS X 中这些新的日历识别符使得 Fundation 跟上了CLDR的步伐:
-
NSCalendar
: 亚历山大日历, 科普特正教使用.Identifier Coptic -
NSCalendar
: 埃塞俄比亚日历, Amete MihretIdentifier Ethiopic Amete Mihret -
NSCalendar
: 埃塞俄比日历, Amete AlemIdentifier Ethiopic Amete Alem -
NSCalendar
: 一个简单的伊斯兰星历.Identifier Islamic Tabular -
NSCalendar
: 沙特阿拉伯伊斯兰日历.Identifier Islamic Umm Al Qura
NSURLCredentialStorage
自从去年NSURLSession
的引入之后,Foundation 的 URL 载入系统并没有太大的改变。但是,新的NSURLCredential
可以让你更加方便地以移步,非闭包的方式获取和存储密码。
import Foundation
let session = NSURLSession()
let task = session.data Task With URL(NSURL(string: "https://nshipster.com"), completion Handler: { data, response, error in
// ...
})
let protection Space = NSURLProtection Space()
NSURLCredential Storage.get Credentials For Protection Space(protection Space: protection Space, task: task, completion Handler: { credentials in
// ...
})
kUTTypeToDoItem
在比较过最新的 API 之后,你可能会注意到大量的新UTI常量。其中,k
引起了我的注意:
import Mobile Core Services
k UTType To Do Item // "public.to-do-item"
作为一个公共类型,iOS 和 OS X 现在提供了统一的方式让 App 之间共享任务。如果你碰巧正在开发一个任务管理工具,正确的整合好这个系统类型应该成为你的首要任务。
kCGImageMetadataShouldExcludeGPS
许多用户完全不知道他们用手机拍摄的大部分照片都包含了 GPS 元数据。更是有数不清的人因为这一个小细节泄露了自己的隐私。
最新的图片 I/O 框架中加入了一个新的选项CGImage
: k
让你方便的控制是否包含 GPS 元数据。
@import UIKit;
@import Image IO;
@import Mobile Core Services;
UIImage *image = ...;
NSURL *file URL = [NSURL file URLWith Path:@"/path/to/output.jpg"];
NSString *UTI = k UTType JPEG;
NSDictionary *options = @{
(__bridge id)k CGImage Destination Lossy Compression Quality: @(0.75),
(__bridge id)k CGImage Metadata Should Exclude GPS: @(YES),
};
CGImage Destination Ref image Destination Ref =
CGImage Destination Create With URL((__bridge CFURLRef)file URL,
(__bridge CFString Ref)UTI,
1,
NULL);
CGImage Destination Add Image(image Destination Ref, [image CGImage], (__bridge CFDictionary Ref)options);
CGImage Destination Finalize(image Destination Ref);
CFRelease(image Destination Ref);
WTF_PLATFORM_IOS
#define WTF_PLATFORM_IOS
已经从 JavaScriptCore 中移除.
WKWebView
UIWeb
已死. WKWeb
万岁.
WKWeb
提供了 Safari 级别的性能,并且在UIWeb
的基础上提供了更多的配置选项:
import Web Kit
let preferences = WKPreferences()
preferences.java Script Can Open Windows Automatically = false
let configuration = WKWeb View Configuration()
configuration.preferences = preferences
let web View = WKWeb View(frame: self.view.bounds, configuration: configuration)
let request = NSURLRequest(URL: NSURL(string: "https://nshipster.com"))
web View.load Request(request)
NSQualityOfService
线程这个概念已经在苹果的框架中被系统性的忽略。这对于开发者而言是件好事。
沿着这个趋势,NSOperation
中新的quality
的属性取代了原来的thread
。通过它可以推迟那些不重要的任务,从而让用户体验更加流畅。
NSQuality
枚举定义了以下值:
-
User
:和图形处理相关的任务,比如滚动和动画。Interactive -
User
:用户请求的任务,但是不需要精确到毫秒级。例如,如果用户请求打开电子邮件 App 来查看邮件。Initiated -
Utility
:周期性的用户请求任务。比如,电子邮件 App 可能被设置成每五分钟自动检查新邮件。但是在系统资源极度匮乏的时候,将这个周期性的任务推迟几分钟也没有大碍。 -
Background
:后台任务,用户可能并不会察觉对这些任务。比如,电子邮件 App 对邮件进行引索以方便搜索。
Quality of Service 将在 iOS 8 和 OS X Yosemite 中广泛的应用,所以留意所有能利用它们的机会。
LocalAuthentication
最后,最令人期待的 iOS 8 新功能之一:LocalAuthentication。自从 iPhone 5S 加入 TouchID,开发者就对它的应用前景垂涎三尺。
想象一下,只要有 CloudKit 和 LocalAuthentication,创建新账号的烦恼讲不复存在。只需要扫描一下你的手就搞定了!
LocalAuthentication 以LAContext
的方式工作,验证声明的规格,然后返回是否验证成功。整个过程中,用户的生物信息都被安全的储存在硬件当中。
LAContext *context = [[LAContext alloc] init];
NSError *error = nil;
if ([context can Evaluate Policy:LAPolicy Device Owner Authentication With Biometrics
error:&error])
{
[context evaluate Policy:LAPolicy Device Owner Authentication With Biometrics
localized Reason:NSLocalized String(@"...", nil)
reply:^(BOOL success, NSError *error) {
if (success) {
// ...
} else {
NSLog(@"%@", error);
}
}];
} else {
NSLog(@"%@", error);
}
虽然这些天每个人都在讨论 Swift,但是作为一个开发者你更应该关注的是这些 iOS 8 和 OS X Yosemite 的新 API。它们可以让你实实在在的做一些事。
如果你想接着探索,dive into the iOS 7.1 to 8.0 API diffs可以让你领会这些变化的重要性。当然,4000 多的新 API,很多只是细微的改变或者将方法改为属性,但是,它们值得拥有!