i​OS 9

撰写、 翻译、 发布于

WWDC 2015 虽不像往届那样精彩纷呈,但却丝毫不缺乏亮点。 watchOS 2 包含改良过的 WatchKit,Apple Watch 硬件访问权限以及表盘插件支持。Swift 也有大量改进,并且宣布了未来的开源计划。全新的框架,包括:Contacts,ContactsUI 和 CoreSpotlight,还有一些新 UIKit 类型,比如:UIStackViewSFSafariViewController

我们会在未来数周甚至数月内深入地探讨这些主要的改进。不过现在,我们先来一起看看 iOS 9 给我们熟悉和热爱的 API 带来了哪些改进。


字符串变形

以前深藏在 Core Foundation 的字符串变形这次被带到了 NSString 和 Swift String 中。这让 Cocoa 这项强大功能变得十分易用,因为不用再去理会桥接 CFStringRef 所带来的麻烦。下面是一些使用新 NSStringTransform* 常量来进行字符串变形的例子:

音译

"privet".stringByApplyingTransform(NSStringTransformLatinToCyrillic, reverse: false)
// "привет"
"안녕하세요".stringByApplyingTransform(NSStringTransformLatinToHangul, reverse: true)
// "annyeonghaseyo"
"annyeonghaseyo".stringByApplyingTransform(NSStringTransformLatinToHangul, reverse: false)
// "안녕하세요"
NSLog(@"%@", [@"privet" stringByApplyingTransform:NSStringTransformLatinToCyrillic reverse:NO]);
// "привет"
NSLog(@"%@", [@"annyeonghaseyo" stringByApplyingTransform:NSStringTransformLatinToHangul reverse:NO]);
// "안녕하세요"
NSLog(@"%@", [@"안녕하세요" stringByApplyingTransform:NSStringTransformLatinToHangul reverse:YES]);
// "annyeonghaseyo"

Unicode 名称

"🐷".stringByApplyingTransform(NSStringTransformToUnicodeName, reverse: false)
// "{PIG FACE}"
NSLog(@"%@", [@"🐷" stringByApplyingTransform:NSStringTransformToUnicodeName reverse:NO]);
// "{PIG FACE}"

规格化用户输入

"Hello! こんにちは! สวัสดี! مرحبا! 您好!"
        .stringByApplyingTransform(NSStringTransformToLatin, reverse: false)?
        .stringByApplyingTransform(NSStringTransformStripDiacritics, reverse: false)?
        .localizedLowercaseString
        .componentsSeparatedByCharactersInSet(NSCharacterSet.whitespaceCharacterSet())
// ["hello!", "kon'nichiha!", "swasdi!", "mrhba!", "nin", "hao!"]
NSString *input = @"Hello! こんにちは! สวัสดี! مرحبا! 您好!";
NSString *processing = [input stringByApplyingTransform:NSStringTransformToLatin reverse:NO];
processing = [processing stringByApplyingTransform:NSStringTransformStripDiacritics reverse:NO];

NSArray<NSString *> *output = [processing.localizedLowercaseString
                               componentsSeparatedByCharactersInSet:[NSCharacterSet whitespaceCharacterSet]];
NSLog(@"%@", output);
// ["hello!", "kon'nichiha!", "swasdi!", "mrhba!", "nin", "hao!"]

想要了解更多,一定不要错过 Mattt 的 CFStringTransform

CLLocationManager.requestLocation

Core Location 包含了一个新的轻量 API,用来单次获取用户位置信息。requestLocation() 使用和连续更新一样的代理方法,在发送完期望精度的位置信息后,会自动将自己关闭:

class ViewController : UIViewController, CLLocationManagerDelegate {
    let locationManager = CLLocationManager()
    // ...

    override func viewDidLoad() {
        super.viewDidLoad()

        locationManager.delegate = self
        locationManager.desiredAccuracy = kCLLocationAccuracyHundredMeters
        locationManager.requestLocation()
    }

   // MARK: - CLLocationManagerDelegate

    func locationManager(manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
        if let location = locations.first {
            print("Current location: \(location)")
        } else {
            // ...
        }
    }

    func locationManager(manager: CLLocationManager, didFailWithError error: NSError) {
        print("Error finding location: \(error.localizedDescription)")
    }
}

Swift 化

iOS 9 和 OS X 10.11 对 Cocoa API 进行了数千项小改进,使 Swift 互用性变得更加安全和简单。这些改进从熟悉的空值标注开始,将隐式打开地参数和返回值变为真正的 Optional 或者非 Optional 的数据类型。

比如,许多 API 将以前 NSArray 类型的返回值从空值改为了空数组,语义上看,它们是同义的,但是非 Optional 数组易用很多。此外,许多 Cocoa API 开始利用 Objective-C 中新加入的泛型语法来提供类型化数组。前面提到 CLLocationManagerDelegatelocationManager(_:didUpdateLocations:) 方法就是这么一个例子:之前 locations 参数是 AnyObject 数组,现在变成了 CLLocation 数组,从而省去了在方法体中还要另外转型的麻烦。

最后,许多之前 Swift 根本无法访问的 API 也被修正了,比如,用来获取特殊 UIAppearance 的代理方法。过去的 appearanceWhenContainedIn: 是用 C 可变参数实现的;新的 appearanceWhenContainedInInstancesOfClasses(_:) 则用数组作为参数:

UIBarButtonItem.appearanceWhenContainedInInstancesOfClasses([UINavigationController.self]).tintColor = UIColor.redColor()
[UIBarButtonItem appearanceWhenContainedInInstancesOfClasses:@[[UINavigationController class]]].tintColor = [UIColor redColor];

可笑的是, Swift 在每次调用这个方法时都会崩溃。 Beta 毕竟是 Beta 啊。

NSFormatter 增进

Contacts 框架包含了用于本地化联系人和地址的 NSFormatter 子类以及一个新 Foundation NSPersonNameComponentsFormatter 类。我们会在未来几周内详细介绍,不过现在先来看看 NSNumberFormatterNSDateFormatter 有哪些新的亮点。

NSNumberFormatter

首先,iOS 9 中 NSNumberFormatter 增加四个额外样式,.OrdinalStyle用于将数字转换为序数形式:

let formatter = NSNumberFormatter()
formatter.numberStyle = .OrdinalStyle

let numbers = [1, 2, 3, 4, 5]
numbers.map { formatter.stringFromNumber($0)! }
// ["1st", "2nd", "3rd", "4th", "5th"]

formatter.locale = NSLocale(localeIdentifier: "es")
numbers.map { formatter.stringFromNumber($0)! }
// ["1º", "2º", "3º", "4º", "5º"]
NSNumberFormatter *formatter = [[NSNumberFormatter alloc] init];
formatter.numberStyle = NSNumberFormatterOrdinalStyle;
NSArray<NSNumber *> *numbers = @[@1, @2, @3, @4, @5];

for (NSNumber *number in numbers) {
    NSLog(@"%@", [formatter stringFromNumber:number]);
}
// "1st", "2nd", "3rd", "4th", "5th"

formatter.locale = [NSLocale localeWithLocaleIdentifier:@"es"];
for (NSNumber *number in numbers) {
    NSLog(@"%@", [formatter stringFromNumber:number]);
}
// "1º", "2º", "3º", "4º", "5º"

其次,现有的 .CurrencyStyle 新增了 .CurrencyPluralStyle.CurrencyISOCodeStyle.CurrencyAccountingStyle。当使用这些新样式的时候,确保你的区域设置中包含语言以及国家和地区,这样才能保证格式器选择正确的货币和表达:

let styles: [NSNumberFormatterStyle] = [.CurrencyStyle, .CurrencyPluralStyle, 
                .CurrencyISOCodeStyle, .CurrencyAccountingStyle]
formatter.locale = NSLocale(localeIdentifier: "en_US")
styles.map {
    formatter.numberStyle = $0
    return formatter.stringFromNumber(-125)!
}
// ["-$125.00", "-125.00 US dollars", "-USD125.00", "($125.00)"]

formatter.locale = NSLocale(localeIdentifier: "es_ES")
styles.map {
    formatter.numberStyle = $0
    return formatter.stringFromNumber(-125)!
}
// ["-125,00 €", "-125,00 euros", "-125,00 EUR", "-125,00 €"]

NSDateFormatter

再次,称 setLocalizedDateFormatFromTemplate(_:)NSDateFormatter 的新方法可能有点将就。早在 iOS 8 它就被加入进来,直到今年的 Internationalization 讲座中才被大家所熟知。这个方法使得定义日期和时间模版变得极其简单;虽然真正的格式化还是由 NSDateFormatter 来完成:

let now = NSDate()

// full date and time
let fullFormatter = NSDateFormatter()
fullFormatter.setLocalizedDateFormatFromTemplate("yyyyMMMMddhhmm")
// month name and year only
let shortFormatter = NSDateFormatter()
shortFormatter.setLocalizedDateFormatFromTemplate("yyMMMM")

fullFormatter.stringFromDate(now)
// "June 23, 2015, 4:56 PM"
shortFormatter.stringFromDate(now)
// "June 15"

// switch locales to "de_DE"
fullFormatter.locale = NSLocale(localeIdentifier: "de_DE")
shortFormatter.locale = NSLocale(localeIdentifier: "de_DE")

fullFormatter.stringFromDate(now)
// "Juni 23, 2015, 4:56 nachm."
shortFormatter.stringFromDate(now)
// "Juni 15"

好了,以上就是 iOS 9 新 API 的大致介绍,虽然还有很多我们没有涉及到的地方。对 iOS 9 或者 OS X 10.11 的哪些新功能最感兴趣呢?参考下苹果的官方文档,然后告诉我们吧

下一篇文章

作为 iOS 开发者,如果想自己独立制作应用,有时可能需要写一些后端代码。即使对于能够胜任这项工作的移动开发者而言,这不仅意味着要写代码,跟多的是长期维护。最糟糕的情况可能并不是大家不喜欢你的应用,而是在巨大流量压力下你的服务器宕机了。

幸运的是,现在我们有 CloudKit 了。苹果替我们操心这些事情,你只管让应用变得完美。