译自 NSHispter。
NDA 终于结束了,我们终于可以聊聊 iOS 7 里超赞的新 API 了。而且新 API 有非常多。苹果在 WWDC Keynote 中说有“1500 个新 API”,。(尽管里面很大一部分只是把 id
换成了 instancetype
,但是不管怎么说还是非常多)
带着版本升级的激动心情,接下来的几周我们会深入讨论 iOS 7 的许多新特性,但是这周,我们来看下那些隐藏颇深的新特性:NSData
Base64 编码, NSURLComponents
, NSProgress
, NSProcessInfo
activities, CIDetectorSmile
, CIDetectorEyeBlink
, SSReadingList
, AVCaptureMetaDataOutput
, AVSpeechSynthesizer
和 MKDistanceFormatter
。
NSData (NSDataBase64Encoding)
Base64 是一种常用的把二进制编码成 ASCII 字符的手段。由于许多常用 web 技术只支持文本,并不支持二进制,所以 Base64 应用十分广泛。例如,CSS 可以用 inline data://
URIs 来内嵌图片,这种形式就经常使用 Base64 编码的文本。另一个例子是 Basic Authentication
headers,它使用 Base64 编码用户名/密码对,稍微比完全明文好一点吧。
长久以来,这个重要的函数压根就没有,数以千计的开发者治好到论坛上随便抓一段代码贴过来就用。如此显而易见的缺失就像 iOS 5 之前的 JSON 一样恼人。
但是现在!iOS 7 终于内置了 Base64:
NSString *string = @"Lorem ipsum dolor sit amet.";
NSString *base64EncodedString = [[string dataUsingEncoding:NSUTF8StringEncoding] base64EncodedStringWithOptions:0];
NSLog(@"%@", base64EncodedString); // @"TG9yZW0gaXBzdW0gZG9sYXIgc2l0IGFtZXQu"
NSURLComponents & NSCharacterSet (NSURLUtilities)
Foundation 框架里面有许多 URI 相关的功能。不过,很多功能是用 NSString
实现的,因为 NSURL
是不可改变的。
NSURLComponents
极大地改善了这种情况。把它当成是 NSMutableURL
就好了:
NSURLComponents *components = [NSURLComponents componentsWithString:@"http://nshipster.com"];
components.path = @"/iOS7";
components.query = @"foo=bar";
NSLog(@"%@", components.scheme); // @"http"
NSLog(@"%@", [components URL]); // @"http://nshipster.com/iOS7?foo=bar"
URL components 的每个属性都有一个 percentEncoded*
的变种(例如 user
和 percentEncodedUser
),这些变种不会对 URI 中的特殊字符进行百分号编码。
你说那些字符算是特殊字符?好吧,这跟字符处在 URL 的哪个部分有关。好消息是 iOS 7 中 NSCharacterSet
增加了一个新的 category 来查询允许出现在 URL 中的字符。
+ (id)URLUserAllowedCharacterSet
+ (id)URLPasswordAllowedCharacterSet
+ (id)URLHostAllowedCharacterSet
+ (id)URLPathAllowedCharacterSet
+ (id)URLQueryAllowedCharacterSet
+ (id)URLFragmentAllowedCharacterSet
NSProgress
NSProgess
是一个有点难描述的类。它既是一个观察者,又是一个委托/协调者,扮演者报告和监控过程的角色。它在 OS X 上的系统级进程进行了整合,不过也可以用于面向用户的 UI。它可以指定暂停和取消的处理逻辑,让这些代码来真正地暂停和取消操作。
任何具有完成状态和总量概念的东西都可以使用 NSProgress
,不管是写入文件的字节数、渲染的帧数,还是要从服务器上下载的文件数。
NSProgress
可以用本地化的方式来汇报总体进度:
NSProgress *progress = [NSProgress progressWithTotalUnitCount:100];
progress.completedUnitCount = 42;
NSLog(@"%@", [progress localizedDescription]); // 42% completed
…或者可以给一个代码块来让操作完全停止:
NSTimer *timer = [NSTimer timerWithTimeInterval:1.0
target:self
selector:@selector(incrementCompletedUnitCount:) userInfo:nil
repeats:YES];
progress.cancellationHandler = ^{
[timer invalidate];
};
[progress cancel];
NSProgess
在 Mac OS X 10.9 Mavericks 下很有用,但是在当前也还是一个包装工作量这个模式的一个很好的类。
NSArray -firstObject
欢呼吧!NSArray
中避免 NSRangeException
的 -lastObject
终于有了对应的取第一个元素对应方法。(好吧,实际上这个方法在 iOS 4 的时候就已经成为私有 API 了,但是现在终于开放出来了)
注意了!
NSArray *array = @[@1, @2, @3];
NSLog(@"First Object: %@", [array firstObject]); // 1
NSLog(@"Last Object: %@", [array lastObject]); // 3
爽!
CIDetectorSmile & CIDetectorEyeBlink
As a random aside, shouldn't it be a cause for concern that the device most capable of taking embarrassing photos of ourselves is also the device most capable of distributing it to millions or people? Just a thought.
iOS 5 以后,Core Image 在 CIDetector
类中加入了面部识别和检测功能。如果检测照片中的人脸还不够炫的话,在 iOS 7 中我们甚至能检测笑脸和闭眼。*发抖*
又一个免费 app 的点子,只保存笑脸照片的相机 app,其中的一段代码可能是这样的:
@import CoreImage;
CIDetector *smileDetector = [CIDetector detectorOfType:CIDetectorSmile
context:context
options:@{CIDetectorTracking: @YES,
CIDetectorAccuracy: CIDetectorAccuracyLow}];
NSArray *features = [smileDetector featuresInImage:image];
if ([features count] > 0) {
UIImageWriteToSavedPhotosAlbum(image, self, @selector(didFinishWritingImage), features);
} else {
self.label.text = @"Say Cheese!"
}
AVCaptureMetaDataOutput
iOS 7 里在 AVCaptureMetaDataOutput
中新增加了扫描 UPC、QR 码、普通条形码和其他变种的方法。只需要添加一个 AVCaptureSession
的输出,实现相应的 captureOutput:didOutputMetadataObjects:fromConnection:
方法:
@import AVFoundation;
AVCaptureSession *session = [[AVCaptureSession alloc] init];
AVCaptureDevice *device = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo];
NSError *error = nil;
AVCaptureDeviceInput *input = [AVCaptureDeviceInput deviceInputWithDevice:device
error:&error];
if (input) {
[session addInput:input];
} else {
NSLog(@"Error: %@", error);
}
AVCaptureMetadataOutput *output = [[AVCaptureMetadataOutput alloc] init];
[output setMetadataObjectsDelegate:self queue:dispatch_get_main_queue()];
[session addOutput:output];
[session startRunning];
#pragma mark - AVCaptureMetadataOutputObjectsDelegate
- (void)captureOutput:(AVCaptureOutput *)captureOutput
didOutputMetadataObjects:(NSArray *)metadataObjects
fromConnection:(AVCaptureConnection *)connection
{
NSString *QRCode = nil;
for (AVMetadataObject *metadata in metadataObjects) {
if ([metadata.type isEqualToString:AVMetadataObjectTypeQRCode]) {
// This will never happen; nobody has ever scanned a QR code... ever
QRCode = [(AVMetadataMachineReadableCodeObject *)metadata stringValue];
break;
}
}
NSLog(@"QR Code: %@", QRCode);
}
AVFoundation
支持你听说过的所有条形码(大概还有一些没听过的):
AVMetadataObjectTypeUPCECode
AVMetadataObjectTypeCode39Code
AVMetadataObjectTypeCode39Mod43Code
AVMetadataObjectTypeEAN13Code
AVMetadataObjectTypeEAN8Code
AVMetadataObjectTypeCode93Code
AVMetadataObjectTypeCode128Code
AVMetadataObjectTypePDF417Code
AVMetadataObjectTypeQRCode
AVMetadataObjectTypeAztecCode
就算没有其他用途,AVCaptureMetaDataOutput
也使得在 iPhone 和 iPad 上创建一个 Passbook 条码读取器变得非常简单。
SSReadingList
即使真正会看保存在稍后阅读中的文章的人很少,可能只比扫描过 QR 码的人多一些。iOS 7 里新的 Safari Services framework 还是带来一个不错的功能:向 Safari 的阅读列表中添加文章。
@import SafariServices;
NSURL *URL = [NSURL URLWithString:@"http://nshipster.com/ios7"];
[[SSReadingList defaultReadingList] addReadingListItemWithURL:URL
title:@"NSHipster"
previewText:@"..."
error:nil];
AVSpeechSynthesizer
语音合成(TTS)技术在 1960 年代后期出现以来,就成为了可用性和恶作剧爱好者的利器。
iOS 7 把 Siri 的方便易用的Speak & Spell 功能带到了一个新的类 AVSpeechSynthesizer
中:
AVSpeechSynthesizer *synthesizer = [[AVSpeechSynthesizer alloc] init];
AVSpeechUtterance *utterance = [AVSpeechUtterance speechUtteranceWithString:@"Hello, World!"];
utterance.rate = AVSpeechUtteranceMinimumSpeechRate; // Tell it to me slowly
[synthesizer speakUtterance:utterance];
MKDistanceFormatter
最后,我们用 NSHipster 会喊出“终于来了!”的另一个类来结束我们的 iOS 7 的又新又炫的新 API 介绍,它就是:MKDistanceFormatter
。
就像上面说的,MKDistanceFormatter
提供了一种把公制/英制距离转换成本地化字符串的方法。
@import CoreLocation;
@import MapKit;
CLLocation *sanFrancisco = [[CLLocation alloc] initWithLatitude:37.775 longitude:-122.4183333];
CLLocation *portland = [[CLLocation alloc] initWithLatitude:45.5236111 longitude:-122.675];
CLLocationDistance distance = [portland distanceFromLocation:sanFrancisco];
MKDistanceFormatter *formatter = [[MKDistanceFormatter alloc] init];
formatter.units = MKDistanceFormatterUnitsImperial;
NSLog(@"%@", [formatter stringFromDistance:distance]); // 535 miles
就是这些了!这只是 iOS 7 超棒的新特性中很小的一部分。想要更多?看下 Apple Developer Center 中的文档 "What's New in iOS 7"。
Comments