iOS6、7、8、9、10新特性匯總和適配說明

iOS6新特性


一、關于內存警告

ios6中廢除了viewDidUnload,viewWillUnload這兩個系統回調,收到內存警告時在didReceiveMemoryWarning中進行相關的處理。

- (void)viewDidUnload {
    [super viewDidUnload];
    // 處理 ios6 以下的系統內存警告系統回調消息
}
 
// 這里處理ios6 的內存警告
- (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning];
    
    float sysVer = [[[UIDevice currentDevice] systemVersion] floatValue];
    //ios6 的特殊處理
    
    if (sysVer >= 6.0f) {
        // 保證 invisible,  因為即使在當前界面也會收到系統回調
        if (self.view.window == nil) {
            //.......
            // 做相關的釋放操作
            self.view = nil;   // 確保下次會重新加載
        }
    }
}
二、關于屏幕旋轉

同樣ios6 廢除了shouldAutorotateToInterfaceOrientation這個旋轉屏幕的設置接口。

必須在兩個新接口中設置旋轉屬性:shouldAutorotate、supportedInterfaceOrientations。

收到旋轉事件后的處理,同樣在willRotateToInterfaceOrientation和didRotateFromInterfaceOrientation中進行。

三、UISwitch

ios6下,新增了以下幾個屬性,可以設置開關的顏色以及背景圖。

@property (nonatomic,  retain) UIColor *tintColor;
 
@property (nonatomic,  retain) UIColor *thumbTintColor;
 
@property (nonatomic,  retain) UIImage *onImage;
 
@property (nonatomic,  retain) UIImage *offImage;
四、UINavigationBar

ios6新增了,設置陰影圖片的屬性。

@property (nonatomic, retain) UIImage *shadowImage;
五、UIImage

可以在ios6下設置圖片的scale比例尺寸了。

+ (UIImage *)imageWithData:(NSData *)data scale:(CGFloat)scale;
 
- (id)initWithData:(NSData *)data scale:(CGFloat)scale;

六、UIRefreshControl

之前蘋果官方是沒有現成的下拉刷新的控件,都是自己實現或者使用比較成熟的開源庫。

ios6蘋果加入了UIRefreshControl,配合UITableView直接實現下拉刷新。

七、UICollectionView

全新的集合控件,應用場景有類似照片墻,瀑布流等。

iOS7新特性


一、已禁用-[UIDevice uniqueIdentifier]

蘋果總是把用戶的隱私看的很重要。-[UIDevice uniqueIdentifier]在iOS5實際在iOS5的時候已經被遺棄了,但是iOS7中已經完全的禁用了它。Xcode5甚至不會允許你編譯包含了指引到-[UIDevice uniqueIdentifier]的app。

此外,iOS7之前的使用了-[UIDevice uniqueIdentifier] 的app如果在iOS7上運行,它不會返回設備的UUID,而是會返回一串字符串,以FFFFFFFF開頭,跟著-[UIDevice identifierForVendor]的十六進制值。

二、UIPasteboard由共享變為沙盒化了

UIPasteboard過去是用來做app之間的數據分享的。UIPasteboard本無問題,但是開發者開始使用它來存儲標識符,和其他的相關app分享這些標識符的時候問題就出現了。有一個使用這種把戲的就是OpenUDID。

在iOS7中,使用 +[UIPasteboard pasteboardWithName:create:]和 +[UIPasteboard pasteboardWithUniqueName]創建剪貼板,而且只對相同的app group可見,這樣就讓OpenUDID不那么有用了。

三、MAC地址不能再用來設別設備

還有一個生成iOS設備唯一標示符的方法是使用iOS設備的Media Access Control(MAC)地址。一個MAC地址是一個唯一的號碼,它是物理網絡層級方面分配給網絡適配器的。這個地址蘋果還有其他的名字,比如說是硬件地址(Hardware Address)或是Wifi地址,都是指同樣的東西。

有很多工程和框架都使用這個方法來生成唯一的設備ID。比如說ODIN。然而,蘋果并不希望有人通過MAC地址來分辨用戶,所以如果你在iOS7系統上查詢MAC地址,它現在只會返回02:00:00:00:00:00。

現在蘋果明確的表明你應該使用-[UIDevice identifierForVendor]或是-[ASIdentifierManager advertisingIdentifier]來作為你框架和應用的唯一標示符。坦白的來說,應對這些變化也不是那么的難,見以下代碼片段:

NSString *identifierForVendor = [[UIDevice currentDevice].identifierForVendor UUIDString];
 
NSString *identifierForAdvertising = [[ASIdentifierManager sharedManager].advertisingIdentifier UUIDString];

每種方法都適配一種特別的用法:

identifierForVendor對供應商來說是唯一的一個值,也就是說,由同一個公司發行的的app在相同的設備上運行的時候都會有這個相同的標識符。然而,如果用戶刪除了這個供應商的app然后再重新安裝的話,這個標識符就會不一致。

advertisingIdentifier會返回給在這個設備上所有軟件供應商相同的 一個值,所以只能在廣告的時候使用。這個值會因為很多情況而有所變化,比如說用戶初始化設備的時候便會改變。

四、iOS現在要求app如需使用麥克風,需要征得用戶同意

以前如果app需要使用用戶的位置,通訊錄,日歷,提醒以及照片,接受推送消息,使用用戶的社交網絡的時候需要征得用戶的同意。現在在iOS7當中,使用麥克風也需要取得用戶同意了。如果用戶不允許app使用麥克風的話,那么需要使用麥克風的app就不能接收不到任何聲音。

以下的代碼是用來查詢用戶是否允許app使用麥克風:

//第一次調用這個方法的時候,系統會提示用戶讓他同意你的app獲取麥克風的數據
// 其他時候調用方法的時候,則不會提醒用戶
// 而會傳遞之前的值來要求用戶同意
[[AVAudioSession sharedInstance] requestRecordPermission:^(BOOL granted) {
    if (granted) {
        // 用戶同意獲取數據
    } else {
        // 可以顯示一個提示框告訴用戶這個app沒有得到允許?
    }
}];

你同時還要注意,如果你在獲得用戶的同意之前使用任何方法來使用麥克風的話,會引起iOS系統彈出以下警示欄:

4673_140117110443_1.jpg
五、[NSArray firstObject]的實現

-[NSArray firstObject]可能是Objective-C中被調用做多的API。在Open Radar上一個簡單的調查顯示有一些需求蘋果已經做了記錄。好消息是現在這些需求已經得到了解決。. firstObject的使用可以追溯到iOS4.0,但是那時僅僅是一個私有方法。在iOS7以前,工程師用下面的方式來使用它:

NSArray *arr = @[];
id item = [arr firstObject];

// 在之前你需要做以下工作
id item = [arr count] > 0 ? arr[0] : nil;

因為上面的方式很平常,有些人將它作為一個類增加到NSArray中,然后創建他們自己的firstObject方法。

這個方法的問題是這個方法的名字必須是唯一的,否則的話這個方法所引發的問題無法預估。

請確保檢查你是否有任何自定義的代碼在NSArray上實現了firstObject,如果有的話看看它是否是必須的,不是必須的話就把它全部移除。

六、增加了instancetype

instancetype讓iOS7API變得更加難懂。蘋果改變了大部分 initializer和簡易構造函數(convenience constructors),用instancetype代替id作返回類型。但是這個instancetype是什么呢?

instancetype用來在聲明一個方法時告訴編譯器其返回類型,它表示返回調用該方法的類的對象。

這比之前返回id的通常做法要好,編譯器可以對返回類型做一些檢查,如果出現錯誤,在編譯時就能提醒你,而不是在程序運行時發生崩潰。

同時,在調用子類方法時,使用它還可以省去對返回值的強制類型轉換,編譯器能夠正確推斷方法的返回值類型。

要說到instancetaype的缺點和優點嗎?基本上,在任何可能的情況下都可以使用它。

七、設置UIImage的渲染模式:UIImage.renderingMode

著色(Tint Color)是iOS7界面中的一個重大改變,你可以設置一個UIImage在渲染時是否使用當前視圖的Tint Color。

UIImage新增了一個只讀屬性:renderingMode,對應的還有一個新增方法:imageWithRenderingMode:,它使用UIImageRenderingMode枚舉值來設置圖片的renderingMode屬性。該枚舉中包含下列值:

// 根據圖片的使用環境和所處的繪圖上下文自動調整渲染模式
UIImageRenderingModeAutomatic 
 
// 始終繪制圖片原始狀態,不使用Tint Color
UIImageRenderingModeAlwaysOriginal 
 
// 始終根據Tint Color繪制圖片,忽略圖片的顏色信息
UIImageRenderingModeAlwaysTemplate

renderingMode屬性的默認值是UIImageRenderingModeAutomatic,即UIImage是否使用Tint Color取決于它顯示的位置。其他情況可以看下面的圖例:

2.png

以下的代碼說明了使用一個既定的rendering模式創建圖片是多么簡單:

UIImage *img = [UIImage imageNamed:@"myimage"];
 
img = [img imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate];

八、tintcolor VS barTintColor

iOS7中你可以使用一個給定的顏色,甚至是記入顏色主題來給整個app著色,幫助你的app脫穎而出。設置app的tint color很簡答,只要使用UIView的新屬性tintColor即可。

這個屬性是否聽上去很熟悉呢?應該很熟悉,有些類,比如說UINaviagtionBar,UISearchBar,UITabBar以及UIToolbar已經有了這么命名的屬性。他們現在有了一個新的屬性:barTintColor。

為了避免使用新屬性的時候犯錯誤,如果你的appp需要支持iOS6以前的系統的時候,請檢查一下。

UINavigationBar *bar = self.navigationController.navigationBar;
UIColor *color = [UIColor greenColor];
 
if ([bar respondsToSelector:@selector(setBarTintColor:)]) { // iOS 7+
    bar.barTintColor = color;
} else { // what year is this? 2012?
    bar.tintColor = color;
}

九、去掉了紋理顏色

紋理顏色?對,不再使用他們了,不能再創建可以展現紋理的顏色。

根據UIInterface.h文件中的注釋,-[UIColor groupTableViewBackgroundColor]應該是要在iOS6當中即被刪除了,但是它僅僅只是不像之前那樣返回紋理顏色了。然而,以下的顏色在iOS7當中被刪除了:

+ (UIColor *)viewFlipsideBackgroundColor;
 
+ (UIColor *)scrollViewTexturedBackgroundColor;
 
+ (UIColor *)underPageBackgroundColor;
十、UIButtonTypeRoundRect被UIButtonTypeSystem取代了

![4.jpg](http://upload-images.jianshu.io/upload_images/1115674-[NSArray firstObject]的實現a6e3528bf458015d.jpg?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

在iOS開發剛開始就陪伴著你的老朋友現在也被刪除了,它就是UIButtonTypeRoundRect ,被新的UIButtonTypeSystem取代了。

如果每次iOS系統的發布都沒有一些新的功能會是什么樣子?這些新功能相信大部分開發者已經知道了,你可能會發現一些新穎的方式將它們整合到你的app中去!

十一、檢查無線路由是否可用

定制一個視頻播放器的能力在iOS版本每次的發布中一直有所進步。比如說,在iOS6之前,你不能在MPVolumeView中改變AirPlay的icon。

在iOS7當中,你可以通過AirPlay,藍牙或是其他的虛線機制了解是否有一個遠程的設備可用。了解它的話,就可以讓你的app在恰當的時候做恰當的事,比如說,在沒有遠程設備的時候就不顯示AirPlay的icon。

以下是新增加到MPVolumeView的新屬性和推送

@property (nonatomic, readonly) BOOL wirelessRoutesAvailable; //  是否有設備可以連接的無線線路?
@property (nonatomic, readonly) BOOL wirelessRouteActive; // 設備現在是否連接上了網絡
NSString *const MPVolumeViewWirelessRoutesAvailableDidChangeNotification;
NSString *const MPVolumeViewWirelessRouteActiveDidChangeNotification;
十二、了解蜂窩網絡

在iOS7之前,是使用Reachability來檢測設備是否連接到WWAN或是Wifi的。iOS7在這個基礎上更進了一步,它會告訴你的設備連接上的是那種蜂窩網絡,比如說是Edge網絡,HSDPA網絡,或是LTE網絡。告訴用戶他們連接上的是哪種網絡可以優化用戶體驗,因為這樣他們會知道網速如何,不會去請求需要高網速的網絡請求。

這是CTTelephonyNetworkInfo的部分功能,它是CoreTelephony框架的一部分。iOS7還增加了currentRadioAccessTechnology屬性和CTRadioAccessTechnologyDidChangeNotification到這個類。還有一些新的字符串常量來定義可能的值,比如說是CTRadioAccessTechnologyLTE。

以下代碼告訴你在app delegate中如何使用這個新功能:

@import CoreTelephony.CTTelephonyNetworkInfo; // new modules syntax!
@interface AppDelegate ()
// we need to keep a reference to the CTTelephonyNetworkInfo object, otherwise the notifications won't be fired!
@property (nonatomic, strong) CTTelephonyNetworkInfo *networkInfo;
@end
 
@implementation ViewController
 
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    // whatever stuff your method does...
    
    self.networkInfo = [[CTTelephonyNetworkInfo alloc] init];
    NSLog(@"Initial cell connection: %@", self.networkInfo.currentRadioAccessTechnology);
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(radioAccessChanged) name:
     CTRadioAccessTechnologyDidChangeNotification object:nil];
    
    // whatever stuff your method does...
}
 
- (void)radioAccessChanged {
    NSLog(@"Now you're connected via %@", self.networkInfo.currentRadioAccessTechnology);
}
 
@end

注意:研究一下CTTelephonyNetworkInfo.h 文件來看看是否有其他無線網絡類型的的字符串常量。如果設備沒有連上的話,currentRadioAccessTechnology 則會返回nil。

十三、通過iCloud同步用戶設備的密碼

iOS7以及Mavericks增加了iCloud Keychain來提供密碼,以及iCloud中一些敏感數據的同步。開發者可以通過keychain中的kSecAttrSynchronizable key來遍歷dictionary對象。

由于直接處理keychain比較難,封裝庫提供了一個簡單的處理keychain的方法。SSKeychain封裝庫可能是最有名的的一個,作為一種福利,現在它支持在iCloud同步。

以下代碼片段顯示了如何使用SSKeychain:

#import <SSKeychain.h>
 
- (BOOL)saveCredentials:(NSError **)error {
    SSKeychainQuery *query = [[SSKeychainQuery alloc] init];
    query.password = @"MySecretPassword";
    query.service = @"MyAwesomeService";
    query.account = @"John Doe";
    query.synchronizable = YES;
    return [query save:&error];
}
 
- (NSString *)savedPassword:(NSError **)error {
    SSKeychainQuery *query = [[SSKeychainQuery alloc] init];
    query.service = @"MyAwesomeService";
    query.account = @"John Doe";
    query.synchronizable = YES;
    query.password = nil;
    if ([query fetch:&error]) {
        return query.password;
    }
    return nil;
}

不要忘記CocoaPods是快速便捷安裝SSKeychian的好方法。

十四、使用NSAttributedString顯示HTML

在app中使用webview有時會讓人非常沮喪,即使只是顯示少量的HTMLneirong ,webview也會消耗大量的內存。現在iOS7讓這些變得簡單了,你可以從用少量代碼在HTML文件中創建一個NSAttributedString,比如:

NSString *html = @"<bold>Wow!</bold> Now <em>iOS</em> can create <h3>NSAttributedString</h3> from HTMLs!";
NSDictionary *options = @{NSDocumentTypeDocumentAttribute: NSHTMLTextDocumentType};
 
NSAttributedString *attrString = [[NSAttributedString alloc] initWithData:[html dataUsingEncoding:NSUTF8StringEncoding] options:options documentAttributes:nil error:nil];

現在你可以在任意的UIKit對象上使用NSAttributedString 了,比如說是一個UILabel或是一個UITextField。

注意:NSHTMLTextDocumentType 只是NSDocumentTypeDocumentAttribute key一種可能的值。你還可以使用NSPlainTextDocumentType,NSRTFTextDocumentType或是NSRTFDTextDocumentType。

你還可以從NSAttributedString中創建一個HTML字符串,如下:

NSAttributedString *attrString; // from previous code
NSDictionary *options = @{NSDocumentTypeDocumentAttribute: NSHTMLTextDocumentType};
 
NSData *htmlData = [attrString dataFromRange:NSMakeRange(0, [attrString length]) documentAttributes:options error:nil];
NSString *htmlString = [[NSString alloc] initWithData:htmlData encoding:NSUTF8StringEncoding];

現在你估計在app中會更多的使用HTML了。

十五、使用原生的Base64

Base64是使用ASCII碼顯示二進制數據的一種流行方法。直到現在,開發者還不得不使用開源的工具來編碼解碼Base64的內容。

現在iOS7引入了以下四種新的NSData方法來操作Base64編碼的數據:

// From NSData.h
- (id)initWithBase64EncodedString:(NSString *)base64String options:(NSDataBase64DecodingOptions)options;
 
- (NSString *)base64EncodedStringWithOptions:(NSDataBase64EncodingOptions)options;
 
- (id)initWithBase64EncodedData:(NSData *)base64Data options:(NSDataBase64DecodingOptions)options;
 
- (NSData *)base64EncodedDataWithOptions:(NSDataBase64EncodingOptions)options;

這些方法可以幫助你輕易的將NSData對象轉化為Base64,或者將Base64轉化為NSData object。見以下的例子:

NSData* sampleData = [@"Some sample data" dataUsingEncoding:NSUTF8StringEncoding];
 
NSString * base64String = [sampleData base64EncodedStringWithOptions:0];
NSLog(@"Base64-encoded string is %@", base64String); // prints "U29tZSBzYW1wbGUgZGF0YQ=="
 
NSData* dataFromString = [[NSData alloc] initWithBase64EncodedString:base64String options:0];
NSLog(@"String is %@",[NSString stringWithUTF8String:[dataFromString bytes]]); // prints "String is Some sample data"

如果你需要支持iOS6或者更早以前的系統,你可以使用以下兩個方法:

/* These methods first appeared in NSData.h on OS X 10.9 and iOS 7.0. They are deprecated in the same releases in favor of
 the methods in the <code>NSDataBase64Encoding</code> category. However, these methods have existed for several releases, so
 they may be used for applications targeting releases prior to OS X 10.9 and iOS 7.0.
 */
- (id)initWithBase64Encoding:(NSString *)base64String;
- (NSString *)base64Encoding;
十六、使用UIApplicationUserDidTakeScreenshotNotification來檢查截圖

在iOS7之前,像Snapshot或是Facebook Poke這樣的app是使用一些很精巧的方法來檢測用戶是否有截圖。然而,iOS7提供一個嶄新的推送方法:UIApplicationUserDidTakeScreenshotNotification。只要像往常一樣訂閱即可知道什么時候截圖了。

注意:UIApplicationUserDidTakeScreenshotNotification 將會在截圖完成之后顯示。現在在截圖截取之前無法得到通知。希望蘋果會在iOS8當中增加UIApplicationUserWillTakeScreenshotNotification。

十七、實現多語言語音合成

如果可以讓app說話會不會很好呢?iOS7加入了兩個新類:AVSpeechSynthesizer 以及AVSpeechUtterance。這兩個類可以給你的app發聲。很有意思不是嗎?有多種語言可供選擇——Siri不會說的語言也有,比如說巴西葡萄牙語。

使用這兩個類給app提供語言合成的功能非常簡單。AVSpeechUtterance 代表你想說什么,如何說。AVSpeechSynthesizer 用來發出這些聲音,見以下代碼片段:

AVSpeechSynthesizer *synthesizer = [[AVSpeechSynthesizer alloc] init];
AVSpeechUtterance *utterance =
[AVSpeechUtterance speechUtteranceWithString:@"Wow, I have such a nice voice!"];
utterance.rate = AVSpeechUtteranceMaximumSpeechRate / 4.0f;
utterance.voice = [AVSpeechSynthesisVoice voiceWithLanguage:@"en-US"]; // defaults to your system language
[synthesizer speakUtterance:utterance];
十八、使用了新的UIScreenEdgePanGestureRecognizer

UIScreenEdgePanGestureRecognizer 繼承自UIPanGestureRecognizer ,它可以讓你從屏幕邊界即可檢測手勢。

使用新的手勢識別器很簡單,見以下:

UIScreenEdgePanGestureRecognizer *recognizer = [[UIScreenEdgePanGestureRecognizer alloc] initWithTarget:self action:@selector(handleScreenEdgeRecognizer:)];
recognizer.edges = UIRectEdgeLeft;
[self.view addGestureRecognizer:recognizer];
十九、使用UIScrollViewKeyboardDismissMode實現了Message app的行為

像Messages app一樣在滾動的時候可以讓鍵盤消失是一種非常好的體驗。然而,將這種行為整合到你的app很難。幸運的是,蘋果給UIScrollView添加了一個很好用的屬性keyboardDismissMode,這樣可以方便很多。

現在僅僅只需要在Storyboard中改變一個簡單的屬性,或者增加一行代碼,你的app可以和辦到和Messages app一樣的事情了。

這個屬性使用了新的UIScrollViewKeyboardDismissMode enum枚舉類型。這個enum枚舉類型可能的值如下:

UIScrollViewKeyboardDismissModeNone        // the keyboard is not dismissed automatically when scrolling
UIScrollViewKeyboardDismissModeOnDrag      // dismisses the keyboard when a drag begins
UIScrollViewKeyboardDismissModeInteractive // the keyboard follows the dragging touch off screen, and may be
pulled upward again to cancel the dismiss

以下是讓鍵盤可以在滾動的時候消失需要設置的屬性:

5.png
二十、使用Core Image來檢測眨眼以及微笑

iOS給Core Image增加了兩種人臉檢測功能:CIDetectorEyeBlink以及CIDetectorSmile。這也就是說你現在可以在照片中檢測微笑以及眨眼。

以下是在app中使用它的方法:

UIImage *image = [UIImage imageNamed:@"myImage"];
CIDetector *detector = [CIDetector detectorOfType:CIDetectorTypeFace
                                          context:nil
                                          options:@{CIDetectorAccuracy: CIDetectorAccuracyHigh}];
 
NSDictionary *options = @{ CIDetectorSmile: @YES, CIDetectorEyeBlink: @YES };
 
NSArray *features = [detector featuresInImage:image.CIImage options:options];
 
for (CIFaceFeature *feature in features) {
    NSLog(@"Bounds: %@", NSStringFromCGRect(feature.bounds));
    
    if (feature.hasSmile) {
        NSLog(@"Nice smile!");
    } else {
        NSLog(@"Why so serious?");
    }
    if (feature.leftEyeClosed || feature.rightEyeClosed) {
        NSLog(@"Open your eyes!");
    }
}
二十一、給UITextView增加了鏈接

現在在iOS添加你自己的Twitter賬戶更加簡單了,現在你可以給一個NSAttributedString增加鏈接了,然后當它被點擊的時候喚起一個定制的action。

首先,創建一個NSAttributedString然后增加給它增加一個NSLinkAttributeName 屬性,見以下:

NSMutableAttributedString *attributedString = [[NSMutableAttributedString alloc] initWithString:@"This is an example by @marcelofabri_"];
[attributedString addAttribute:NSLinkAttributeName
                         value:@"username://marcelofabri_"
                         range:[[attributedString string] rangeOfString:@"@marcelofabri_"]];
 
 
NSDictionary *linkAttributes = @{NSForegroundColorAttributeName: [UIColor greenColor],
                                 NSUnderlineColorAttributeName: [UIColor lightGrayColor],
                                 NSUnderlineStyleAttributeName: @(NSUnderlinePatternSolid)};
 
// assume that textView is a UITextView previously created (either by code or Interface Builder)
textView.linkTextAttributes = linkAttributes; // customizes the appearance of links
textView.attributedText = attributedString;
textView.delegate = self;

這樣就可以讓鏈接在文本中顯示。然而,你也可以控制當鏈接被點擊的時候會發生什么,實現這個可以使用UITextViewDelegate協議的新的shouldInteractWithURL方法,就像這樣:

- (BOOL)textView:(UITextView *)textView shouldInteractWithURL:(NSURL *)URL inRange:(NSRange)characterRange {
    if ([[URL scheme] isEqualToString:@"username"]) {
        NSString *username = [URL host];
        // do something with this username
        // ...
        return NO;
    }
    return YES; // let the system open this URL
}

iOS8新特性

一、UIAlertController對alert&actionSheet的封裝

UIAlertController.h

提示框按鈕的選擇

typedef NS_ENUM(NSInteger, UIAlertActionStyle) {
    
    UIAlertActionStyleDefault = 0,
    
    UIAlertActionStyleCancel,
    
    UIAlertActionStyleDestructive
    
} NS_ENUM_AVAILABLE_IOS(8_0);

提示框的樣式

typedef NS_ENUM(NSInteger, UIAlertControllerStyle) {
    
    UIAlertControllerStyleActionSheet = 0,
    
    UIAlertControllerStyleAlert
    
} NS_ENUM_AVAILABLE_IOS(8_0);
 
NS_CLASS_AVAILABLE_IOS(8_0) @interface UIAlertAction : NSObject <NSCopying>

創建提示框按鈕

+ (instancetype)actionWithTitle:(NSString *)title style:(UIAlertActionStyle)style handler:(void (^)(UIAlertAction *action))handler;
 
@property (nonatomic, readonly) NSString *title;
 
@property (nonatomic, readonly) UIAlertActionStyle style;
 
@property (nonatomic, getter=isEnabled) BOOL enabled;
 
@end
 
NS_CLASS_AVAILABLE_IOS(8_0) @interface UIAlertController : UIViewController

創建提示框

+ (instancetype)alertControllerWithTitle:(NSString *)title message:(NSString *)message preferredStyle:(UIAlertControllerStyle)preferredStyle;

添加按鈕

- (void)addAction:(UIAlertAction *)action;
 
@property (nonatomic, readonly) NSArray *actions;

添加文本輸入框

- (void)addTextFieldWithConfigurationHandler:(void (^)(UITextField *textField))configurationHandler;
 
@property (nonatomic, readonly) NSArray *textFields;
 
@property (nonatomic, copy) NSString *title;
 
@property (nonatomic, copy) NSString *message;
 
@property (nonatomic, readonly) UIAlertControllerStyle preferredStyle;

簡單實用示例:

// 1.創建提示框對象,默認是actionSheet效果
UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"注意" message:@"我的呈現方式變了" preferredStyle:UIAlertControllerStyleAlert];
 
// 2.創建取消按鈕并添加到提示框上
[alert addAction:[UIAlertAction actionWithTitle:@"取消" style:UIAlertActionStyleCancel handler:^(UIAlertAction *action) {
    
    NSLog(@"取消按鈕被點擊了");
}]];

// 3.呈現提示框
[self presentViewController:alert animated:YES completion:nil];
二、UIPopoverController直接通過present方式呈現

UIViewController.h

typedef NS_ENUM(NSInteger, UIModalPresentationStyle) {
    
    UIModalPresentationFullScreen = 0,
    
    UIModalPresentationPageSheet NS_ENUM_AVAILABLE_IOS(3_2),
    
    UIModalPresentationFormSheet NS_ENUM_AVAILABLE_IOS(3_2),
    
    UIModalPresentationCurrentContext NS_ENUM_AVAILABLE_IOS(3_2),
    
    UIModalPresentationCustom NS_ENUM_AVAILABLE_IOS(7_0),
    
    UIModalPresentationOverFullScreen NS_ENUM_AVAILABLE_IOS(8_0),
    
    UIModalPresentationOverCurrentContext NS_ENUM_AVAILABLE_IOS(8_0),
    
    UIModalPresentationPopover NS_ENUM_AVAILABLE_IOS(8_0),
    
    UIModalPresentationNone NS_ENUM_AVAILABLE_IOS(7_0) = -1,
    
};
 
@property (nonatomic,readonly) UIPopoverPresentationController *popoverPresentationController NS_AVAILABLE_IOS(8_0);

使用示例:

// 1.創建內容控制器
UITableViewController *contentVc = [[UITableViewController alloc] init];
 
// 2.1 設置呈現方式
contentVc.modalPresentationStyle = UIModalPresentationPopover;
 
// 2.2設置在導航欄的左邊按鈕呈現
contentVc.popoverPresentationController.barButtonItem = self.navigationItem.leftBarButtonItem;
 
// 3.呈現
[self presentViewController:contentVc animated:YES completion:nil];

以前的方式:

// 1.創建內容控制器
UITableViewController *contentVc = [[UITableViewController alloc] init];
 
// 2.創建popover
UIPopoverController *popover = [[UIPopoverController alloc] initWithContentViewController:contentVc];
 
popover.popoverContentSize = CGSizeMake(100, 100);
 
// 3.呈現
[popover presentPopoverFromBarButtonItem:self.navigationItem.leftBarButtonItem permittedArrowDirections:UIPopoverArrowDirectionAny animated:YES];
三、獲取用戶授權的用戶隱私保護

地圖定位示例 :

// 導入定位框架
#import <CoreLocation/CoreLocation.h>
 
@interface ViewController ()<CLLocationManagerDelegate>
 
// 設置定位對象
@property(nonatomic,strong)CLLocationManager* maneger;
 
@end
 
@implementation ViewController
 
- (void)viewDidLoad {
    [super viewDidLoad];
    
    // 當使用iOS8定位的時候需要請求用戶授權,且在info.plist里添加字段NSLocationAlwaysUsageDescription 請求用戶授權的描述
    // iOS7僅僅需要在info.plist里添加字段Privacy - Location Usage Description 請求用戶授權的描述
    // 不需要再寫下面的代碼
    if (IOS8) {
        [self.maneger requestAlwaysAuthorization];//請求用戶授權 
    }
    
    // 開啟定位
    [self.maneger startUpdatingLocation];
    
}
四、針對屏幕適配應運而生的size classes

size classes是為了解決storyboard只能訂制一種屏幕樣式的問題,它不再是具體的尺寸,而是抽象尺寸通過寬/高 的compact、any、regular 組成了九種組合包含了所有蘋果設備的尺寸。

iOS9新特性


一、網絡適配

iOS9系統發送的網絡請求將統一使用TLS 1.2 SSL。采用TLS 1.2 協議,目的是強制增強數據訪問安全,而且系統Foundation框架下的相關網絡請求,將不再默認使用HTTP等不安全的網絡協議,而默認采用TLS 1.2。服務器因此需要更新,以解析相關數據。如不更新,可通過在 info.plist 中聲明,倒退回不安全的網絡請求。

什么是SSL/TLS?跟HTTP和HTTPS有什么關系?

跟往常一樣,先說結論:

HTTP + SSL/TLS + TCP = HTTPS

TLS 是 SSL 新的別稱。舉個例子:

“TLS1.0”之于“SSL3.1”,猶“公元2015”之于“民國104”,或者是“一千克”之于“一公斤”,或者是“半斤”之于“八兩”:稱呼不同,但意思相同。

SSL 3.0版本之后的迭代版本被重新命名為TLS 1.0,也就是說:

TLS 1.0 = SSL 3.1

所以他們是一個東西,我們平常也經常簡單見到 “SSL/TLS” 這種說法。常用的是下面這些:

SSL 2.0
 
SSL 3.0
 
TLS 1.0 (SSL 3.1)
 
TLS 1.1 (SSL 3.1)
 
TLS 1.2 (SSL 3.1)

那為什么標題是“使用HTTPS”而沒有提及SSL和TLS什么事? 要理解這個,要看下一個公式:

HTTP + SSL/TLS + TCP = HTTPS

打個比方:如果原來的 HTTP 是塑料水管,容易被戳破;那么如今新設計的 HTTPS 就像是在原有的塑料水管之外,再包一層金屬水管。一來,原有的塑料水管照樣運行;二來,用金屬加固了之后,不容易被戳破。

目前,應用最廣泛的是TLS 1.0,接下來是SSL 3.0。但是,主流瀏覽器都已經實現了TLS 1.2的支持。Apple讓你的HTTP采用SSL/TLS協議,就是讓你從HTTP轉到HTTPS。

以前的HTTP不是也能用嗎?為什么要用SSL/TLS,閑得慌?!Apple是不是又在反人類?

不使用SSL/TLS的HTTP通信,就是不加密的通信!

所有信息明文傳播,帶來了三大風險:

竊聽風險(eavesdropping):第三方可以獲知通信內容。

篡改風險(tampering):第三方可以修改通信內容。

冒充風險(pretending):第三方可以冒充他人身份參與通信。

SSL/TLS協議是為了解決這三大風險而設計的,希望達到:

所有信息都是加密傳播,第三方無法竊聽。

具有校驗機制,一旦被篡改,通信雙方會立刻發現。

配備身份證書,防止身份被冒充。

如何適配?---弱弱地問下:加班要多久?

正如文章開頭所說:

TLS 1.2 協議 強制增強數據訪問安全 系統 Foundation 框架下的相關網絡請求,將不再默認使用 HTTP 等不安全的網絡協議,而默認采用 TLS 1.2。服務器因此需要更新,以解析相關數據。如不更新,可通過在 Info.plist 中聲明,倒退回不安全的網絡請求。

方案一:立即讓公司的服務端升級使用TLS 1.2。

方案二:雖Apple不建議,但可通過在 Info.plist 中聲明,倒退回不安全的網絡請求依然能讓App訪問指定http,甚至任意的http。

info.plist 配置中的XML源碼如下所示:

6.jpg

上面是比較嚴謹的做法,指定了能訪問哪些特定的HTTP。當然也有暴力的做法: 徹底倒退回不安全的HTTP網絡請求,能任意進行HTTP請求,比如你在開發一款瀏覽器App,或者你想偷懶,或者后臺想偷懶,或者公司不給你升級服務器。但目前Apple的官方文檔并未提及如何在 info.plist 配置可以參考本文:http://blog.6ag.cn/1065.html

二、更靈活的后臺定位

如果不適配iOS9,就不能偷偷在后臺定位。不過蘋果將允許出現這種場景:

同一App中的多個location manager,一些只能在前臺定位,另一些可在后臺定位,并可隨時開啟或者關閉特定location manager的后臺定位。

如何偷偷在后臺定位:

// 1. 實例化定位管理器
_locationManager = [[CLLocationManager alloc] init];
 
// 2. 設置代理
_locationManager.delegate = self;
 
// 3. 定位精度
[_locationManager setDesiredAccuracy:kCLLocationAccuracyBest];
 
// 4.請求用戶權限:分為:?只在前臺開啟定位?在后臺也可定位,
//注意:建議只請求?和?中的一個,如果兩個權限都需要,只請求?即可,
//??這樣的順序,將導致bug:第一次啟動程序后,系統將只請求?的權限,?的權限系統不會請求,只會在下一次啟動應用時請求?
if ([[[UIDevice currentDevice] systemVersion] floatValue] >= 8) {
    //[_locationManager requestWhenInUseAuthorization];//?只在前臺開啟定位
    [_locationManager requestAlwaysAuthorization];//?在后臺也可定位
}
 
// 5.iOS9新特性:將允許出現這種場景:同一app中多個location manager:一些只能在前臺定位,另一些可在后臺定位(并可隨時禁止其后臺定位)。
if ([[[UIDevice currentDevice] systemVersion] floatValue] >= 9) {
    _locationManager.allowsBackgroundLocationUpdates = YES;
}
 
// 6. 更新用戶位置
[_locationManager startUpdatingLocation];

但是如果照著這種方式嘗試,而沒有配置info.plist,100%你的程序會崩潰掉,并報錯:

*** Assertion failure in -[CLLocationManager setAllowsBackgroundLocationUpdates:], /BuildRoot/Library/Caches/com.apple.xbs/Sources/CoreLocationFramework_Sim/CoreLocation-1808.1.5/Framework/CoreLocation/CLLocationManager.m:593

要將 info.plist 配置如下:

7.png

對應的 Info.plist 的XML源碼是:

8.jpg
三、Bitcode

bitcode的理解應該是把程序編譯成的一種過渡代碼,然后蘋果再把這個過渡代碼編譯成可執行的程序。bitcode也允許蘋果在后期重新優化我們程序的二進制文件,有類似于App瘦身的思想。未來Watch應用須包含Bitcode,iOS不強制,但Xcode7默認會開啟Bitcode。

用了xcode7的編譯器編譯之前沒問題的項目可能會出現下列報錯。

XXXX’ does not contain bitcode. You must rebuild it with bitcode enabled (Xcode setting ENABLE_BITCODE), obtain an updated library from the vendor, or disable bitcode forthistarget. forarchitecture arm64

問題的原因是:某些第三方庫還不支持bitcode。要不然是等待庫的開發者升級了此項功能我們更新庫,要不就是把這個bitcode禁用。禁用Bitcode,方法見下圖:

9.png
四、企業級分發

iOS9之前,企業級分發十分方便:點擊App出現“信任按鈕”。

iOS9以后,企業級分發ipa包將遭到與Mac上dmg安裝包一樣的待遇。默認不能安裝,也不再出現“信任按鈕”,必須讓用戶進行gif圖中的設置。

10.gif
五、URL scheme

URL scheme一般使用的場景是應用程序有分享或跳其他平臺授權的功能,分享或授權后再跳回來。在iOS8并沒有做過多限制,在iOS9中,如果使用URL scheme必須在"info.plist"中將你要在外部調用的URL scheme列為白名單,否則不能使用。

canOpenURL: failed forURL : "mqzone://qqapp"- error: "This app is not allowed to query for scheme mqzone"

具體的解決方案也是要在info.plist中設置 LSApplicationQueriesSchemes 類型為數組,下面添加所有你用到的scheme

11.png

推薦一篇博客: http://awkwardhare.com/post/121196006730/quick-take-on-ios-9-url-scheme-changes

其中最關鍵的是以下部分:

If you call the “canOpenURL” method on a URL that is not in your whitelist, it will return “NO”, even if there is an app installed that has registered to handle this scheme. A “This app is not allowed to query for scheme xxx” syslog entry will appear.

If you call the “openURL” method on a URL that is not in your whitelist, it will fail silently. A “This app is not allowed to query for scheme xxx” syslog entry will appear.

六、新字體

iOS8中,字體是Helvetica,中文的字體有點類似于“華文細黑”。只是蘋果手機自帶渲染,所以看上去可能比普通的華文細黑要美觀。iOS9中,中文系統字體變為了專為中國設計的“蘋方” 有點類似于一種word字體“幼圓”。字體有輕微的加粗效果,并且最關鍵的是字體間隙變大了!

所以很多原本寫死了width的label可能會出現“...”的情況。

12.png
13.png

上面這兩張圖也可以直觀的看出同一個界面,同一個label的變化。

所以為了在界面顯示上不出錯,就算是固定長度的文字也還是建議使用sizetofit 或者ios向上取整 ceilf() 或者提前計算。

CGSize size = [title sizeWithAttributes:@{NSFontAttributeName: [UIFont systemFontOfSize:14.0f]}];
CGSize adjustedSize = CGSizeMake(ceilf(size.width), ceilf(size.height));
七、tableview

雖然現在的iOS9已經推送正式版了,但是iOS9使用時還是會感覺到App比以前更加卡頓了,tableView拖動時卡頓顯示的最為明顯。 并且之前遇到一個bug,原本好的項目用xcode7一編譯,tableView刷新出了問題 ,[tableView reloadData]無效,有一行cell明明改變了但是刷新不出來。 感覺可能是這個方法和某種新加的特性沖突了,猜測可能是reloadData的操作被推遲到下一個RunLoop執行最終失效。

解決的方法是,注釋[tableView reloadData],改用局部刷新,問題居然就解決了。

[self.tableView reloadSections:[NSIndexSet indexSetWithIndex:0] withRowAnimation:UITableViewRowAnimationNone];
八、iPad適配Slide Over 和 Split View

iPad適配Slide Over 和 Split View,若想適配multi tasking特性,唯一的建議:

棄純代碼,改用storyboard、xib,縱觀蘋果WWDC所有Demo均是如此。

Mysteries of Auto Layout, Part 1
What's New in Storyboards
Implementing UI Designs in Interface Builder
Getting Started with Multitasking on iPad in iOS 9
Optimizing Your App for Multitasking on iPad in iOS

iOS10新特性


一.系統判斷方法失效:

在你的項目中,當需要判斷系統版本的話,不要使用下面的方法:

#define isiOS10 ([[[[UIDevice currentDevice] systemVersion] substringToIndex:1] intValue]>=10)

它會永遠返回 NO,substringToIndex:1在iOS 10 會被檢測成 iOS 1了,
應該使用下面的這些方法:Objective-C 中這樣寫:

#define SYSTEM_VERSION_EQUAL_TO(v) ([[[UIDevice currentDevice] systemVersion] compare:v options:NSNumericSearch] == NSOrderedSame)#define SYSTEM_VERSION_GREATER_THAN(v) ([[[UIDevice currentDevice] systemVersion] compare:v options:NSNumericSearch] == NSOrderedDescending)#define SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(v) ([[[UIDevice currentDevice] systemVersion] compare:v options:NSNumericSearch] != NSOrderedAscending)#define SYSTEM_VERSION_LESS_THAN(v) ([[[UIDevice currentDevice] systemVersion] compare:v options:NSNumericSearch] == NSOrderedAscending)#define SYSTEM_VERSION_LESS_THAN_OR_EQUAL_TO(v) ([[[UIDevice currentDevice] systemVersion] compare:v options:NSNumericSearch] != NSOrderedDescending)

或者使用:

if ([[NSProcessInfo processInfo] isOperatingSystemAtLeastVersion:(NSOperatingSystemVersion){.majorVersion = 9, .minorVersion = 1, .patchVersion = 0}]) { NSLog(@"Hello from > iOS 9.1");}if ([NSProcessInfo.processInfo isOperatingSystemAtLeastVersion:(NSOperatingSystemVersion){9,3,0}]) { NSLog(@"Hello from > iOS 9.3");}

或者使用:

if (NSFoundationVersionNumber > NSFoundationVersionNumber_iOS_9_0) { // do stuff for iOS 9 and newer} else { // do stuff for older versions than iOS 9}

有時候會缺少一些常量,NSFoundationVersionNumber是在NSObjCRuntime.h
中定義的,作為Xcode7.3.1的一部分,我們設定常熟范圍從iPhone OS 2到

define NSFoundationVersionNumber_iOS_8_4 1144.17

``
,在iOS 10(Xcode 8)中,蘋果補充了缺少的數字,設置有未來的版本.

#define NSFoundationVersionNumber_iOS_9_0 1240.1#define NSFoundationVersionNumber_iOS_9_1 1241.14#define NSFoundationVersionNumber_iOS_9_2 1242.12#define NSFoundationVersionNumber_iOS_9_3 1242.12#define NSFoundationVersionNumber_iOS_9_4 1280.25#define NSFoundationVersionNumber_iOS_9_x_Max 1299

Swift中這樣寫:

if NSProcessInfo().isOperatingSystemAtLeastVersion(NSOperatingSystemVersion(majorVersion: 10, minorVersion: 0, patchVersion: 0)) { // 代碼塊}

或者使用

if #available(iOS 10.0, *) {  // 代碼塊} else { // 代碼塊}
二.隱私數據訪問問題:

你的項目中訪問了隱私數據,比如:相機,相冊,聯系人等,在Xcode8中打開編譯的話,統統會crash,控制臺會輸出下面這樣的日志:

這是因為iOS對用戶的安全和隱私的增強,在申請很多私有權限的時候都需要添加描述,但是,在使用Xcode 8之前的Xcode還是使用系統的權限通知框.要想解決這個問題,只需要在info.plist
添加NSContactsUsageDescription
key, value自己隨意填寫就可以,這里列舉出對應的key(Source Code模式下):

<!-- 相冊 --> 
<key>NSPhotoLibraryUsageDescription</key> <string>App需要您的同意,才能訪問相冊</string>
<!-- 相機-->
<key>NSCameraUsageDescription</key> <string>App需要您的同意,才能訪問相機</string> 
<!-- 麥克風 -->    
<key>NSMicrophoneUsageDescription</key> <string>App需要您的同意,才能訪問麥克風</string> 
<!-- 位置 -->    
<key>NSLocationUsageDescription</key> <string>App需要您的同意,才能訪問位置</string> 
<!-- 在使用期間訪問位置 -->
<key>NSLocationWhenInUseUsageDescription</key> <string>App需要您的同意,才能在使用期間訪問位置</string> 
<!-- 始終訪問位置 -->    
<key>NSLocationAlwaysUsageDescription</key> <string>App需要您的同意,才能始終訪問位置</string> 
<!-- 日歷 -->    
<key>NSCalendarsUsageDescription</key> <string>App需要您的同意,才能訪問日歷</string> 
<!-- 提醒事項 -->    
<key>NSRemindersUsageDescription</key> <string>App需要您的同意,才能訪問提醒事項</string> 
<!-- 運動與健身 -->    
<key>NSMotionUsageDescription</key> <string>App需要您的同意,才能訪問運動與健身</string> 
<!-- 健康更新 -->    
<key>NSHealthUpdateUsageDescription</key> <string>App需要您的同意,才能訪問健康更新 </string> 
<!-- 健康分享 -->    
<key>NSHealthShareUsageDescription</key> <string>App需要您的同意,才能訪問健康分享</string> 
<!-- 藍牙 -->    
<key>NSBluetoothPeripheralUsageDescription</key> <string>App需要您的同意,才能訪問藍牙</string> 
<!-- 媒體資料庫 -->    
<key>NSAppleMusicUsageDescription</k

如果不起作用,可以請求后臺權限,類似于這樣:

<key>UIBackgroundModes</key><array> 
<!-- 在這里寫上你在后臺模式下要使用權限對應的key --> 
<string>location</string>...</array>

或者在Xcode里選中當前的target
,選擇Capabilities
,找到Background Modes
,打開它,在里面選擇對應權限

三.UIColor的問題

官方文檔中說:大多數core
開頭的圖形框架和AVFoundation
都提高了對擴展像素和寬色域色彩空間的支持.通過圖形堆棧擴展這種方式比以往支持廣色域的顯示設備更加容易。現在對UIKit擴展可以在sRGB的色彩空間下工作,性能更好,也可以在更廣泛的色域來搭配sRGB顏色.如果你的項目中是通過低級別的api自己實現圖形處理的,建議使用sRGB,也就是說在項目中使用了RGB轉化顏色的建議轉換為使用sRGB,在UIColor
類中新增了兩個api:

- (UIColor *)initWithDisplayP3Red:(CGFloat)displayP3Red green:(CGFloat)green blue:(CGFloat)blue alpha:(CGFloat)alpha NS_AVAILABLE_IOS(10_0);+ (UIColor *)colorWithDisplayP3Red:(CGFloat)displayP3Red green:(CGFloat)green blue:(CGFloat)blue alpha:(CGFloat)alpha NS_AVAILABLE_IOS(10_0);
四.真彩色的顯示

真彩色的顯示會根據光感應器來自動的調節達到特定環境下顯示與性能的平衡效果,如果需要這個功能的話,可以在info.plist
里配置(在Source Code模式下):
<key>UIWhitePointAdaptivityStyle</key>

它有五種取值,分別是:

<string>UIWhitePointAdaptivityStyleStandard</string> // 標準模式<string>UIWhitePointAdaptivityStyleReading</string> // 閱讀模式<string>UIWhitePointAdaptivityStylePhoto</string> // 圖片模式<string>UIWhitePointAdaptivityStyleVideo</string> // 視頻模式<string>UIWhitePointAdaptivityStyleStandard</string> // 游戲模式

也就是說如果你的項目是閱讀類的,就選擇UIWhitePointAdaptivityStyleReading
這個模式,五種模式的顯示效果是從上往下遞減,也就是說如果你的項目是圖片處理類的,你選擇的是閱讀模式,給選擇太好的效果會影響性能.

五.ATS的問題
  1. 在iOS 9的時候,默認非HTTS的網絡是被禁止的,我們可以在info.plist
    文件中添加NSAppTransportSecurity
    字典,將NSAllowsArbitraryLoads
    設置為YES
    來禁用ATS;
  2. 從2017年1月1日起,,所有新提交的 app 默認不允許使用NSAllowsArbitraryLoads
    來繞過ATS的限制,默認情況下你的 app 可以訪問加密足夠強的(TLS V1.2以上)HTTPS內容;
  3. 可以選擇使用NSExceptionDomains
    設置白名單的方式對特定的域名開放HTTP內容來通過審核,比如說你的應用集成了第三方的登錄分享SDK,可以通過這種方式來做,下面以新浪SDK作為示范(Source Code 模式下):
<key>NSAppTransportSecurity</key> <dict> <key>NSExceptionDomains</key> <dict> <key>sina.cn</key> <dict> <key>NSThirdPartyExceptionMinimumTLSVersion</key> <string>TLSv1.0</string> <key>NSThirdPartyExceptionRequiresForwardSecrecy</key> <false/> <key>NSIncludesSubdomains</key> <true/> </dict> <key>weibo.cn</key> <dict> <key>NSThirdPartyExceptionMinimumTLSVersion</key> <string>TLSv1.0</string> <key>NSThirdPartyExceptionRequiresForwardSecrecy</key> <false/> <key>NSIncludesSubdomains</key> <true/> </dict> <key>weibo. com</key> <dict> <key>NSThirdPartyExceptionMinimumTLSVersion</key> <string>TLSv1.0</string> <key>NSThirdPartyExceptionRequiresForwardSecrecy</key> <false/> <key>NSIncludesSubdomains</key> <true/> </dict> <key>sinaimg.cn</key> <dict> <key>NSThirdPartyExceptionMinimumTLSVersion</key> <string>TLSv1.0</string> <key>NSThirdPartyExceptionRequiresForwardSecrecy</key> <false/> <key>NSIncludesSubdomains</key> <true/> </dict> <key>sinajs.cn</key> <dict> <key>NSThirdPartyExceptionMinimumTLSVersion</key> <string>TLSv1.0</string> <key>NSThirdPartyExceptionRequiresForwardSecrecy</key> <false/> <key>NSIncludesSubdomains</key> <true/> </dict> <key>sina.com.cn</key> <dict> <key>NSThirdPartyExceptionMinimumTLSVersion</key> <string>TLSv1.0</string> <key>NSThirdPartyExceptionRequiresForwardSecrecy</key> <false/> <key>NSIncludesSubdomains</key> <true/> </dict> </dict> </dict>
  1. 在iOS 10 中info.plist
    文件新加入了NSAllowsArbitraryLoadsInWebContent`` 鍵,允許任意web`頁面加載,同時蘋果會用 ATS 來保護你的app;
  2. 安全傳輸不再支持SSLv3, 建議盡快停用SHA13DES算法;
六.UIStatusBar的問題:

在iOS10中,如果還使用以前設置UIStatusBar`類型或者控制隱藏還是顯示的方法,會報警告,方法過期,如下圖:

上面方法到 iOS 10 不能使用了,要想修改UIStatusBar的樣式或者狀態使用下圖中所示的屬性或方法:

@property(nonatomic, readonly) UIStatusBarStyle preferredStatusBarStyle NS_AVAILABLE_IOS(7_0) __TVOS_PROHIBITED; // Defaults to UIStatusBarStyleDefault@property(nonatomic, readonly) BOOL prefersStatusBarHidden NS_AVAILABLE_IOS(7_0) __TVOS_PROHIBITED; // Defaults to NO- (UIStatusBarStyle)preferredStatusBarStyle NS_AVAILABLE_IOS(7_0) __TVOS_PROHIBITED; // Defaults to UIStatusBarStyleDefault- (BOOL)prefersStatusBarHidden NS_AVAILABLE_IOS(7_0) __TVOS_PROHIBITED; // Defaults to NO// Override to return the type of animation that should be used for status bar changes for this view controller. This currently only affects changes to prefersStatusBarHidden.- (UIStatusBarAnimation)preferredStatusBarUpdateAnimation NS_AVAILABLE_IOS(7_0) __TVOS_PROHIBITED; // Defaults to UIStatusBarAnimationFade
七、UITextField

在iOS 10 中,UITextField
新增了textContentType字段,是UITextContentType類型,它是一個枚舉,作用是可以指定輸入框的類型,以便系統可以分析出用戶的語義.是電話類型就建議一些電話,是地址類型就建議一些地址.可以在
#import <UIKit/UITextInputTraits.h>
文件中,查看textContentType
字段,有以下可以選擇的類型:

UIKIT_EXTERN UITextContentType const UITextContentTypeName NS_AVAILABLE_IOS(10_0); 
UIKIT_EXTERN UITextContentType const UITextContentTypeNamePrefix NS_AVAILABLE_IOS(10_0);
UIKIT_EXTERN UITextContentType const UITextContentTypeGivenName NS_AVAILABLE_IOS(10_0);
UIKIT_EXTERN UITextContentType const UITextContentTypeMiddleName NS_AVAILABLE_IOS(10_0);
UIKIT_EXTERN UITextContentType const UITextContentTypeFamilyName NS_AVAILABLE_IOS(10_0);
UIKIT_EXTERN UITextContentType const UITextContentTypeNameSuffix NS_AVAILABLE_IOS(10_0);
UIKIT_EXTERN UITextContentType const UITextContentTypeNickname NS_AVAILABLE_IOS(10_0);
UIKIT_EXTERN UITextContentType const UITextContentTypeJobTitle NS_AVAILABLE_IOS(10_0);
UIKIT_EXTERN UITextContentType const UITextContentTypeOrganizationName NS_AVAILABLE_IOS(10_0);
UIKIT_EXTERN UITextContentType const UITextContentTypeLocation NS_AVAILABLE_IOS(10_0);
UIKIT_EXTERN UITextContentType const UITextContentTypeFullStreetAddress NS_AVAILABLE_IOS(10_0);
UIKIT_EXTERN UITextContentType const UITextContentTypeStreetAddressLine1 NS_AVAILABLE_IOS(10_0);
UIKIT_EXTERN UITextContentType const UITextContentTypeStreetAddressLine2 NS_AVAILABLE_IOS(10_0);
UIKIT_EXTERN UITextContentType const UITextContentTypeAddressCity NS_AVAILABLE_IOS(10_0);
UIKIT_EXTERN UITextContentType const UITextContentTypeAddressState NS_AVAILABLE_IOS(10_0);
UIKIT_EXTERN UITextContentType const UITextContentTypeAddressCityAndState NS_AVAILABLE_IOS(10_0);
UIKIT_EXTERN UITextContentType const UITextContentTypeSublocality NS_AVAILABLE_IOS(10_0);
UIKIT_EXTERN UITextContentType const UITextContentTypeCountryName NS_AVAILABLE_IOS(10_0);
UIKIT_EXTERN UITextContentType const UITextContentTypePostalCode NS_AVAILABLE_IOS(10_0);
UIKIT_EXTERN UITextContentType const UITextContentTypeTelephoneNumber NS_AVAILABLE_IOS(10_0);
UIKIT_EXTERN UITextContentType const UITextContentTypeEmailAddress NS_AVAILABLE_IOS(10_0);
UIKIT_EXTERN UITextContentType const UITextContentTypeURL NS_AVAILABLE_IOS(10_0);
UIKIT_EXTERN UITextContentType const UITextContentTypeCreditCardNumber NS_AVAILABLE_IOS(10_0);
八、UserNotifications(用戶通知)

iOS 10 中將通知相關的 API 都統一了,在此基礎上很多用戶定義的通知,并且可以捕捉到各個通知狀態的回調.以前通知的概念是:大家想接受的提前做好準備,然后一下全兩分發,沒收到也不管了,也不關心發送者,現在的用戶通知做成了類似于網絡請求,先發一個request
得到response
的流程,還封裝了error
,可以在各個狀態的方法中做一些額外的操作,并且能獲得一些字段,比如發送者之類的.這個功能的頭文件是:#import <UserNotifications/UserNotifications.h>
主要有以下文件:

#import <UserNotifications/NSString+UserNotifications.h>
#import <UserNotifications/UNError.h>
#import <UserNotifications/UNNotification.h>
#import <UserNotifications/UNNotificationAction.h>
#import <UserNotifications/UNNotificationAttachment.h>
#import <UserNotifications/UNNotificationCategory.h>
#import <UserNotifications/UNNotificationContent.h>
#import <UserNotifications/UNNotificationRequest.h>
#import <UserNotifications/UNNotificationResponse.h>
#import <UserNotifications/UNNotificationSettings.h>
#import <UserNotifications/UNNotificationSound.h>
#import <UserNotifications/UNNotificationTrigger.h>
#import <UserNotifications/UNUserNotificationCenter.h>
#import <UserNotifications/UNNotificationServiceExtension.h>
九.UICollectionViewCell的的優化

在iOS 10 之前,UICollectionView上面如果有大量cell,當用戶活動很快的時候,整個UICollectionView的卡頓會很明顯,為什么會造成這樣的問題,這里涉及到了iOS 系統的重用機制,當cell準備加載進屏幕的時候,整個cell都已經加載完成,等待在屏幕外面了,也就是整整一行cell都已經加載完畢,這就是造成卡頓的主要原因,專業術語叫做:掉幀.要想讓用戶感覺不到卡頓,我們的app必須幀率達到60幀/秒,也就是說每幀16毫秒要刷新一次.
iOS 10 之前UICollectionViewCell的生命周期是這樣的:

  1. 用戶滑動屏幕,屏幕外有一個cell準備加載進來,把cell從reusr隊列拿出來,然后調用prepareForReuse
    方法,在這個方法里面,可以重置cell的狀態,加載新的數據;
  2. 繼續滑動,就會調用cellForItemAtIndexPath
    方法,在這個方法里面給cell賦值模型,然后返回給系統;
  3. cell馬上進去屏幕的時候,就會調用willDisplayCell
    方法,在這個方法里面我們還可以修改cell,為進入屏幕做最后的準備工作;
  4. 執行完willDisplayCell
    方法后,cell就進去屏幕了.當cell完全離開屏幕以后,會調用didEndDisplayingCell
    方法.

iOS 10 UICollectionViewCell的生命周期是這樣的:

  1. 用戶滑動屏幕,屏幕外有一個cell準備加載進來,把cell從reusr隊列拿出來,然后調用prepareForReuse
    方法,在這里當cell還沒有進去屏幕的時候,就已經提前調用這個方法了,對比之前的區別是之前是cell的上邊緣馬上進去屏幕的時候就會調用該方法,而iOS 10 提前到cell還在屏幕外面的時候就調用;
  2. cellForItemAtIndexPath
    中創建cell,填充數據,刷新狀態等操作,相比于之前也提前了;
  3. 用戶繼續滑動的話,當cell馬上就需要顯示的時候我們再調用willDisplayCell
    方法,原則就是:何時需要顯示,何時再去調用willDisplayCell
    方法;
  4. 當cell完全離開屏幕以后,會調用didEndDisplayingCell
    方法,跟之前一樣,cell會進入重用隊列.在iOS 10 之前,cell只能從重用隊列里面取出,再走一遍生命周期,并調用cellForItemAtIndexPath
    創建或者生成一個cell.在iOS 10 中,系統會cell保存一段時間,也就是說當用戶把cell滑出屏幕以后,如果又滑動回來,cell不用再走一遍生命周期了,只需要調用willDisplayCell
    方法就可以重新出現在屏幕中了.iOS 10 中,系統是一個一個加載cell的,二以前是一行一行加載的,這樣就可以提升很多性能;iOS 10 新增加的Pre-Fetching預加載
    這個是為了降低UICollectionViewCell在加載的時候所花費的時間,在 iOS 10 中,除了數據源協議和代理協議外,新增加了一個UICollectionViewDataSourcePrefetching
    協議,這個協議里面定義了兩個方法:
- (void)collectionView:(UICollectionView *)collectionView prefetchItemsAtIndexPaths:(NSArray<NSIndexPath *> *)indexPaths NS_AVAILABLE_IOS(10_0);- (void)collectionView:(UICollectionView *)collectionView cancelPrefetchingForItemsAtIndexPaths:(NSArray<NSIndexPath *> *)indexPaths NS_AVAILABLE_IOS(10_0);

ColletionView prefetchItemsAt indexPaths
這個方法是異步預加載數據的,當中的indexPaths
數組是有序的,就是item接收數據的順序;

CollectionView cancelPrefetcingForItemsAt indexPaths

這個方法是可選的,可以用來處理在滑動中取消或者降低提前加載數據的優先級.注意:這個協議并不能代替之前讀取數據的方法,僅僅是輔助加載數據.Pre-Fetching預加載對UITableViewCell同樣適用.

十、 UIRefreshControl的使用

在iOS 10 中, UIRefreshControl可以直接在UICollectionViewUITableView中使用,并且脫離了UITableViewController.現在RefreshControlUIScrollView的一個屬性.使用方法:

UIRefreshControl *refreshControl = [[UIRefreshControl alloc] init]; [refreshControl addTarget:self action:@selector(loadData) forControlEvents:UIControlEventValueChanged]; collectionView.refreshControl = refreshControl;

本文部分內容來自網絡整理,如有錯誤請留言指出,謝謝!

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容