- (BOOL) isOperatingSystemAtLeastVersion:(NSOperatingSystemVersion)version;
对于判断手机等设备的操作系统版本,相比于之前的[[UIDevice currentDevice] systemVersion] 和NSFoundationVersionNumber而言,现在有了新的更有效的方法:
NSProcessInfo -isOperatingSystemAtLeastVersion
import Foundation
let yosemite = NSOperatingSystemVersion(majorVersion: 10, minorVersion: 10, patchVersion: 0)
NSProcessInfo().isOperatingSystemAtLeastVersion(yosemite) // false
NSProcessInfo *info = [[NSProcessInfo alloc]init];
NSOperatingSystemVersion y = info.operatingSystemVersion;
NSLog(@"主版本%d- 次版本:%d- 补丁版本%d",y.majorVersion,y.minorVersion,y.patchVersion);
//=设置中查看的系统版本 x.x.x
注意:在做兼容性测试的时候还是应该使用SomeClass.class或respondsToSelector:。 Swift和C中的编译器宏可以用来根据不同生成配置和目标来选择代码。
Foundation中严重缺失的一项功能就是不能处理重量和长度单位转换。在iOS 8和OS X Yosemite中,引入了三个新类NSEnergyFormatter,NSMassFormatter和NSLengthFormatter来弥补。
这使得Foundation中的 NSFormatter的子类中特性设置子类的数量增加了一倍,过去仅仅有NSNumberFormatter, NSDateFormatter, & NSByteCountFormatter.
虽然这些都是Foundation新添加的子类,但是它们主要都是应用在HealthKit框架中。
NSEnergyFormatter使用焦尔(Joules)作为能量的原始单位,当处理健康信息时,则使用卡路里(Calories).
let energyFormatter = NSEnergyFormatter()
energyFormatter.forFoodEnergyUse = true
let joules = 10_000.0
print(energyFormatter.stringFromJoules(joules)) // "2.39 Cal"
NSEnergyFormatter *energy = [[NSEnergyFormatter alloc]init];
energy.forFoodEnergyUse = YES;
double joules = 10000.0;
NSString *jj = [energy stringFromJoules:joules];
NSLog(@"食物富含的热量是 %@ 焦尔",jj);
let massFormatter = NSMassFormatter()
let kilograms = 60.0
print(massFormatter.stringFromKilograms(kilograms)) // "132 lb"
let lengthFormatter = NSLengthFormatter()
let meters = 5_000.0
print(lengthFormatter.stringFromMeters(meters)) // "3.107 mi"
NSLengthFormatter *length = [[NSLengthFormatter alloc]init];
double meters = 100.0;
NSString *mm = [length stringFromMeters:meters];
NSLog(@"博尔特是 %@ 赛跑最快的男人",mm);
在iOS 8的健康框架的发展中, CMStepCounter被在新版本中被舍弃了. CMPedometer作为它的改良版本不仅可以即时获取离散的点数据,并且可以同时跟踪脚步和距离,甚至计算总共爬了多少级楼梯。
在M7芯片以后,是可以实现如此神奇的能力。
import CoreMotion
let lengthFormatter = NSLengthFormatter()
let pedometer = CMPedometer()
pedometer.startPedometerUpdatesFromDate(NSDate()) { data, error in
if let data = data {
print("Steps Taken: \(data.numberOfSteps)")
if let distance = data.distance?.doubleValue {
print("Distance: \(lengthFormatter.stringFromMeters(distance))")
let time = data.endDate.timeIntervalSinceDate(data.startDate)
let speed = distance / time
print("Speed: \(lengthFormatter.stringFromMeters(speed)) / s")
}
}
}
#import
CMPedometer *pedometer = [[CMPedometer alloc]init];
//判断记步功能
if ([CMPedometer isStepCountingAvailable]) {
[pedometer startPedometerUpdatesFromDate:[NSDate date] withHandler:^(CMPedometerData * _Nullable pedometerData, NSError * _Nullable error) {
//
if (error) {
NSLog(@"error = %@",error);
} else {
NSLog(@"%@",pedometerData);
}
}];
}else{
NSLog(@"记步功能不可用");
}
在支持的设备上,CMPedometer对floorsAscended/ floorsDescended的统计可使用CMAltimeter进行扩充,以获得更精细的垂直距离:
import CoreMotion
let altimeter = CMAltimeter()
if CMAltimeter.isRelativeAltitudeAvailable() {
altimeter.startRelativeAltitudeUpdatesToQueue(NSOperationQueue.mainQueue()) { data, error in
if let data = data {
print("Relative Altitude: \(data.relativeAltitude)")
}
}
}
#import
CMAltimeter *altimeter = [[CMAltimeter alloc]init];
if ([CMAltimeter isRelativeAltitudeAvailable]) {
//
[altimeter startRelativeAltitudeUpdatesToQueue:[NSOperationQueue mainQueue] withHandler:^(CMAltitudeData * _Nullable altitudeData, NSError * _Nullable error) {
//
if (error) {
NSLog(@"error = %@",error);
} else {
NSLog(@"altitudeData = %@",altitudeData);
}
}];
} else {
NSLog(@"测绘相对高度功能不可用");
}
CLFloor是iOS 8中的新API,CoreMotion中的新功能体现了苹果公司的雄心勃勃的室内导航计划。这些信息将会在静谧的局部测绘应用中扮演重要的角色。
import CoreLocation
class LocationManagerDelegate: NSObject, CLLocationManagerDelegate {
func locationManager(manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
if let floor = locations.first?.floor {
print("Current Floor: \(floor.level)")
}
}
}
let manager = CLLocationManager()
manager.delegate = LocationManagerDelegate()
manager.startUpdatingLocation()
#import
@interface ViewController ()<CLLocationManagerDelegate>
@end
CLLocationManager *locManager = [[CLLocationManager alloc]init];
NSLog(@"本人所在地点位置信息为:%@",locManager.location);
if ([CLLocationManager locationServicesEnabled]) {
//
CLLocation *location = [[CLLocation alloc] initWithLatitude:39.0f longitude:116.0f];
CLFloor *floor = location.floor;
NSLog(@"目标地点相对于地面高度为:%ld",(long)floor.level);
} else {
NSLog(@"请打开定位服务!");
}
作为一个框架,HealthKit包含着大量的子类和常量。要想全部理解,HKStatistics是一个很好的开始。
HealthKit管理着所有的生理信息,例如:心率,卡路里摄入量,血氧等等,并且通过统一的API聚合在一起。
下面这个例子演示了如何从一天的连续数据中,挖掘和获取单独的数据:
import HealthKit
let collection: HKStatisticsCollection? = ...
let statistics: HKStatistics? = collection?.statisticsForDate(NSDate())
let sources: [HKSource] = statistics?.sources ?? []
for source in sources {
if let quantity = statistics?.sumQuantityForSource(source) {
if quantity.isCompatibleWithUnit(HKUnit.gramUnitWithMetricPrefix(.Kilo)) {
let massFormatter = NSMassFormatter()
let kilograms = quantity.doubleValueForUnit(HKUnit.gramUnitWithMetricPrefix(.Kilo))
print(massFormatter.stringFromKilograms(kilograms))
}
if quantity.isCompatibleWithUnit(HKUnit.meterUnit()) {
let lengthFormatter = NSLengthFormatter()
let meters = quantity.doubleValueForUnit(HKUnit.meterUnit())
print(lengthFormatter.stringFromMeters(meters))
}
if quantity.isCompatibleWithUnit(HKUnit.jouleUnit()) {
let energyFormatter = NSEnergyFormatter()
let joules = quantity.doubleValueForUnit(HKUnit.jouleUnit())
print(energyFormatter.stringFromJoules(joules))
}
}
}
HKStatistics *statistics = [[HKStatisticsCollection alloc]statisticsForDate:[NSDate dateWithTimeIntervalSinceNow:-60*60*24*16.00f]];
NSArray *sources = statistics.sources;
for (HKSource *source in sources) {
//
HKQuantity *quantity = [statistics sumQuantityForSource:source];
if (quantity) {
//
if ([quantity isCompatibleWithUnit:[HKUnit gramUnitWithMetricPrefix:HKMetricPrefixKilo]]) {
//
NSMassFormatter *massF = [[NSMassFormatter alloc]init];
double kilo = [quantity doubleValueForUnit:[HKUnit gramUnitWithMetricPrefix:HKMetricPrefixKilo]];
NSString *kiloStr = [massF stringFromKilograms:kilo];
NSLog(@"------ %@",kiloStr);
} else if([quantity isCompatibleWithUnit:[HKUnit meterUnit]]) {
//
NSLengthFormatter *lengthF = [[NSLengthFormatter alloc]init];
double meterS = [quantity doubleValueForUnit:[HKUnit meterUnit]];
NSString *meterStr = [lengthF stringFromMeters:meterS];
NSLog(@"+++++++ %@",meterStr);
} else if([quantity isCompatibleWithUnit:[HKUnit jouleUnit]]) {
//
NSEnergyFormatter *energyF = [[NSEnergyFormatter alloc]init];
double joulE = [quantity doubleValueForUnit:[HKUnit jouleUnit]];
NSString *jouleStr = [energyF stringFromJoules:joulE];
NSLog(@"======= %@",jouleStr);
}
} else {
//
NSLog(@"quantity is not exit!");
}
}
NSHipster也将会在未来涵盖更多的HealthKit信息,让我们持续关注吧。
在许多方面,WWDC 2014也是苹果查漏补遗的一年,比如给NSStream添加了新的initializer(再也不用调用CFStreamCreatePairWithSocketToHost了),这就是:+[NSStream getStreamsToHostWithName:port:inputStream:outputStream:]
var inputStream: NSInputStream?
var outputStream: NSOutputStream?
NSStream.getStreamsToHostWithName("nshipster.com",
port: 5432,
inputStream: &inputStream,
outputStream: &outputStream)
//初始化NSStream
NSInputStream *inputStream = [[NSInputStream alloc]init];
NSOutputStream *outputStream = [[NSOutputStream alloc]init];
[NSStream getStreamsToHostWithName:@"nshipster.com" port:8080 inputStream:&inputStream outputStream:&outputStream];
这又是一个NSString小而实用的更新:
let string = "Café"
let substring = "É"
string.localizedCaseInsensitiveContainsString(substring) // true
这是一个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中,但是结果如下:
iOS 8和OS X中这些新的日历识别符使得Fundation跟上了CLDR的步伐:
N
自从去年NSURLSession的引入之后,Foundation的URL载入系统并没有太大的改变。但是,新的NSURLCredentialStorage可以让你更加方便地以异步,非闭包的方式获取和存储证书。
import Foundation
let session = NSURLSession()
let task = session.dataTaskWithURL(NSURL(string: "http://nshipster.com")!) { data, response, error in
// ...
}
let protectionSpace = NSURLProtectionSpace()
let credentialStorage = NSURLCredentialStorage()
credentialStorage.getCredentialsForProtectionSpace(protectionSpace, task: task) { credentials in
// ...
}
在比较过最新的API之后,你可能会注意到大量的新UTI常量。其中,kUTTypeToDoItem引起了我的注意:
import MobileCoreServices
kUTTypeToDoItem // "public.to-do-item"
作为一个公共类,iOS和OS X现在提供了统一的方式让App之间共享任务。如果你碰巧正在开发一个任务管理工具,正确的整合好这个系统类型应该成为你的首要任务。
许多用户完全不知道他们用手机拍摄的大部分照片都包含了GPS元数据。更是有数不清的人因为这一个小细节泄露了自己的隐私。
最新的图片I/O框架中加入了一个新的选项CGImageDestination:kCGImageMetadataShouldExcludeGPS让你方便的控制是否包含GPS元数据:
import UIKit
import ImageIO
import MobileCoreServices
let image = ...
let fileURL = NSURL(fileURLWithPath: "/path/to/output.jpg")
let options: NSDictionary = [kCGImageDestinationLossyCompressionQuality as NSString: 0.75,
kCGImageMetadataShouldExcludeGPS as NSString: true]
if let imageDestination = CGImageDestinationCreateWithURL(fileURL, kUTTypeJPEG, 1, nil),
let cgImage = image.CGImage
{
CGImageDestinationAddImage(imageDestination, cgImage, options)
CGImageDestinationFinalize(imageDestination)
}
@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);
#define WTF_PLATFORM_IOS 已经从JavaScriptCore中移除,以后会变成废弃不可用.
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)
@import WebKit;
WKPreferences *Preces = [[WKPreferences alloc]init];
[Preces setJavaScriptCanOpenWindowsAutomatically:NO];
WKWebViewConfiguration *Config = [[WKWebViewConfiguration alloc]init];
Config.preferences = Preces;
WKWebView *webView = [[WKWebView alloc] initWithFrame:self.window.inputView.frame configuration:Config];
NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"http://nshipster.com"]];
[webView loadRequest:request];
Threads这个概念已经在苹果的框架中被系统性的忽略。这对于开发者而言是件好事。
沿着这个趋势,NSOperation中新的qualityOfService的属性取代了原来的threadPriority。通过它可以推迟那些不重要的任务,从而让用户体验更加流畅。
NSQualityOfService枚举定义了以下值:
Quality of Service将在iOS 8和OS X Yosemite中广泛的应用,所以持续关注它在未来的表现吧。
最后,最令人期待的iOS 8新功能之一:LocalAuthentication。自从iPhone 5S加入TouchID,开发者就对它的应用前景垂涎三尺。
想象一下,只要有CloudKit和LocalAuthentication,创建新账号的烦恼讲不复存在。只需要扫描一下你的手就搞定了!
LocalAuthentication以LAContext的方式工作,验证声明的规格,然后返回是否验证成功。整个过程中,用户的生物信息都被安全的储存在硬件当中。
let context = LAContext()
var error: NSError?
if context.canEvaluatePolicy(.DeviceOwnerAuthenticationWithBiometrics, error: &error) {
context.evaluatePolicy(.DeviceOwnerAuthenticationWithBiometrics, localizedReason: "...") { success, error in
if success {
// ...
} else {
print("Error: \(error)")
}
}
} else {
print("Error: \(error)")
}
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);
}
最后的最后,祝大家编程愉快!