iOS8的一些好玩的升级

一、NSProcessInfo

- (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中的编译器宏可以用来根据不同生成配置和目标来选择代码。

新的NSFormatter子类

Foundation中严重缺失的一项功能就是不能处理重量和长度单位转换。在iOS 8和OS X Yosemite中,引入了三个新类NSEnergyFormatter,NSMassFormatter和NSLengthFormatter来弥补。

这使得Foundation中的 NSFormatter的子类中特性设置子类的数量增加了一倍,过去仅仅有NSNumberFormatter, NSDateFormatter, & NSByteCountFormatter.

虽然这些都是Foundation新添加的子类,但是它们主要都是应用在HealthKit框架中。

  1. NSEnergyFormatter

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);
  1. NSMassFormatter
    虽然质量是物质存在的基本单位, 在HealthKit中,它主要指的是体重.
    是的,质量和重量是不同的,但这是编程,而不是科学课,所以不要钻牛角尖。
let massFormatter = NSMassFormatter()
let kilograms = 60.0
print(massFormatter.stringFromKilograms(kilograms)) // "132 lb"
  1. NSLengthFormatter
    NSFormatter的最后一个新子类是NSLengthFormatter. 我们可以把它想象为MKDistanceFormatter的优化。
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);

CMPedometer

在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 <CoreMotion/CoreMotion.h>
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(@"记步功能不可用"); 
    }

CMAltimeter

在支持的设备上,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 <CoreMotion/CoreMotion.h>
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

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 <CoreLocation/CoreLocation.h>
@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(@"请打开定位服务!");
    }

HKStatistics

作为一个框架,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信息,让我们持续关注吧。

NSStream +getStreamsToHostWithName

在许多方面,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 -localizedCaseInsensitiveContainsString

这又是一个NSString小而实用的更新:

let string = "Café"
let substring = "É"

string.localizedCaseInsensitiveContainsString(substring) // true

CTRubyAnnotationRef

这是一个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中,但是结果如下:
这里写图片描述

New Calendar Identifiers

iOS 8和OS X中这些新的日历识别符使得Fundation跟上了CLDR的步伐:

N

  1. SCalendarIdentifierCoptic: 亚历山大日历, Coptic Orthodox Church(科普特正教)使用.
  2. NSCalendarIdentifierEthiopicAmeteMihret: 埃塞俄比亚日历, Amete Mihret
  3. NSCalendarIdentifierEthiopicAmeteAlem: 埃塞俄比日历, Amete Alem
  4. NSCalendarIdentifierIslamicTabular: 一个简单的伊斯兰星历
  5. NSCalendarIdentifierIslamicUmmAlQura: 沙特阿拉伯伊斯兰日历.

NSURLCredentialStorage

自从去年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
    // ...
}

kUTTypeToDoItem

在比较过最新的API之后,你可能会注意到大量的新UTI常量。其中,kUTTypeToDoItem引起了我的注意:

import MobileCoreServices

kUTTypeToDoItem // "public.to-do-item"

作为一个公共类,iOS和OS X现在提供了统一的方式让App之间共享任务。如果你碰巧正在开发一个任务管理工具,正确的整合好这个系统类型应该成为你的首要任务。

kCGImageMetadataShouldExcludeGPS

许多用户完全不知道他们用手机拍摄的大部分照片都包含了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);

WTF_PLATFORM_IOS

#define WTF_PLATFORM_IOS 已经从JavaScriptCore中移除,以后会变成废弃不可用.

WKWebView

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];

NSQualityOfService

Threads这个概念已经在苹果的框架中被系统性的忽略。这对于开发者而言是件好事。
沿着这个趋势,NSOperation中新的qualityOfService的属性取代了原来的threadPriority。通过它可以推迟那些不重要的任务,从而让用户体验更加流畅。
NSQualityOfService枚举定义了以下值:

  1. UserInteractive:和图形处理相关的任务,比如滚动和动画。
  2. UserInitiated:用户请求的任务,但是不需要精确到毫秒级。例如,如果用户请求打开电子邮件App来查看邮件。
  3. Utility:周期性的用户请求任务。比如,电子邮件App可能被设置成每五分钟自动检查新邮件。但是在系统资源极度匮乏的时候,将这个周期性的任务推迟几分钟也没有大碍。

Quality of Service将在iOS 8和OS X Yosemite中广泛的应用,所以持续关注它在未来的表现吧。

LocalAuthentication

最后,最令人期待的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);
}

最后的最后,祝大家编程愉快!

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值