今天博主有一個iOS7,8,9新特性彙總的需求,遇到了一些困難點,在此和你們分享,但願可以共同進步.html
蘋果老是把用戶的隱私看的很重要。-[UIDevice uniqueIdentifier]在iOS5實際在iOS5的時候已經被遺棄了,可是iOS7中已經徹底的禁用了它。Xcode5甚至不會容許你編譯包含了指引到-[UIDevice uniqueIdentifier]的app。ios
此外,iOS7以前的使用了-[UIDevice uniqueIdentifier] 的app若是在iOS7上運行,它不會返回設備的UUID,而是會返回一串字符串,以FFFFFFFF開頭,跟着-[UIDevice identifierForVendor]的十六進制值。web
UIPasteboard過去是用來作app之間的數據分享的。UIPasteboard本無問題,可是開發者開始使用它來存儲標識符,和其餘的相關app分享這些標識符的時候問題就出現了。有一個使用這種把戲的就是OpenUDID。數組
在iOS7中,使用 +[UIPasteboard pasteboardWithName:create:]和 +[UIPasteboard pasteboardWithUniqueName]建立剪貼板,並且只對相同的app group可見,這樣就讓OpenUDID不那麼有用了。xcode
還有一個生成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]來做爲你框架和應用的惟一標示符。坦白的來講,應對這些變化也不是那麼的難,見如下代碼片斷:服務器
1
2
3
|
NSString *identifierForVendor = [[UIDevice currentDevice].identifierForVendor UUIDString];
NSString *identifierForAdvertising = [[ASIdentifierManager sharedManager].advertisingIdentifier UUIDString];
|
每種方法都適配一種特別的用法:網絡
identifierForVendor對供應商來講是惟一的一個值,也就是說,由同一個公司發行的的app在相同的設備上運行的時候都會有這個相同的標識符。然而,若是用戶刪除了這個供應商的app而後再從新安裝的話,這個標識符就會不一致。app
advertisingIdentifier會返回給在這個設備上全部軟件供應商相同的 一個值,因此只能在廣告的時候使用。這個值會由於不少狀況而有所變化,好比說用戶初始化設備的時候便會改變。
之前若是app須要使用用戶的位置,通信錄,日曆,提醒以及照片,接受推送消息,使用用戶的社交網絡的時候須要徵得用戶的贊成。如今在iOS7當中,使用麥克風也須要取得用戶贊成了。若是用戶不容許app使用麥克風的話,那麼須要使用麥克風的app就不能接收不到任何聲音。
如下的代碼是用來查詢用戶是否容許app使用麥克風:
1
2
3
4
5
6
7
8
9
10
|
//第一次調用這個方法的時候,系統會提示用戶讓他贊成你的app獲取麥克風的數據
// 其餘時候調用方法的時候,則不會提醒用戶
// 而會傳遞以前的值來要求用戶贊成
[[AVAudioSession sharedInstance] requestRecordPermission:^(BOOL granted) {
if (granted) {
// 用戶贊成獲取數據
} else {
// 能夠顯示一個提示框告訴用戶這個app沒有獲得容許?
}
}];
|
你同時還要注意,若是你在得到用戶的贊成以前使用任何方法來使用麥克風的話,會引發iOS系統彈出如下警示欄:
-[NSArray firstObject]多是Objective-C中被調用作多的API。在Open Radar上一個簡單的調查顯示有一些需求蘋果已經作了記錄。好消息是如今這些需求已經獲得瞭解決。. firstObject的使用能夠追溯到iOS4.0,可是那時僅僅是一個私有方法。在iOS7之前,工程師用下面的方式來使用它:
1
2
3
4
5
|
NSArray *arr = @[];
id item = [arr firstObject];
// 在以前你須要作如下工做
id item = [arr count] > 0 ? arr[0] : nil;
|
由於上面的方式很日常,有些人將它做爲一個類增長到NSArray中,而後建立他們本身的firstObject方法。
這個方法的問題是這個方法的名字必須是惟一的,不然的話這個方法所引起的問題沒法預估。
請確保檢查你是否有任何自定義的代碼在NSArray上實現了firstObject,若是有的話看看它是不是必須的,不是必須的話就把它所有移除。
instancetype讓iOS7API變得更加難懂。蘋果改變了大部分 initializer和簡易構造函數(convenience constructors),用instancetype代替id做返回類型。可是這個instancetype是什麼呢?
instancetype用來在聲明一個方法時告訴編譯器其返回類型,它表示返回調用該方法的類的對象。
這比以前返回id的一般作法要好,編譯器能夠對返回類型作一些檢查,若是出現錯誤,在編譯時就能提醒你,而不是在程序運行時發生崩潰。
同時,在調用子類方法時,使用它還能夠省去對返回值的強制類型轉換,編譯器可以正確推斷方法的返回值類型。
要說到instancetaype的缺點和優勢嗎?基本上,在任何可能的狀況下均可以使用它。
着色(Tint Color)是iOS7界面中的一個重大改變,你能夠設置一個UIImage在渲染時是否使用當前視圖的Tint Color。
UIImage新增了一個只讀屬性:renderingMode,對應的還有一個新增方法:imageWithRenderingMode:,它使用UIImageRenderingMode枚舉值來設置圖片的renderingMode屬性。該枚舉中包含下列值:
1
2
3
4
5
6
7
8
|
// 根據圖片的使用環境和所處的繪圖上下文自動調整渲染模式
UIImageRenderingModeAutomatic
// 始終繪製圖片原始狀態,不使用Tint Color
UIImageRenderingModeAlwaysOriginal
// 始終根據Tint Color繪製圖片,忽略圖片的顏色信息
UIImageRenderingModeAlwaysTemplate
|
renderingMode屬性的默認值是UIImageRenderingModeAutomatic,即UIImage是否使用Tint Color取決於它顯示的位置。其餘狀況能夠看下面的圖例:
如下的代碼說明了使用一個既定的rendering模式建立圖片是多麼簡單:
1
2
3
|
UIImage *img = [UIImage imageNamed:@"myimage"];
img = [img imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate];
|
iOS7中你可使用一個給定的顏色,甚至是記入顏色主題來給整個app着色,幫助你的app脫穎而出。設置app的tint color很簡答,只要使用UIView的新屬性tintColor便可。
這個屬性是否聽上去很熟悉呢?應該很熟悉,有些類,好比說UINaviagtionBar,UISearchBar,UITabBar以及UIToolbar已經有了這麼命名的屬性。他們如今有了一個新的屬性:barTintColor。
爲了不使用新屬性的時候犯錯誤,若是你的appp須要支持iOS6之前的系統的時候,請檢查一下。
1
2
3
4
5
6
7
8
|
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當中被刪除了:
1
2
3
4
5
|
+ (UIColor *)viewFlipsideBackgroundColor;
+ (UIColor *)scrollViewTexturedBackgroundColor;
+ (UIColor *)underPageBackgroundColor;
|
在iOS開發剛開始就陪伴着你的老朋友如今也被刪除了,它就是UIButtonTypeRoundRect ,被新的UIButtonTypeSystem取代了。
若是每次iOS系統的發佈都沒有一些新的功能會是什麼樣子?這些新功能相信大部分開發者已經知道了,你可能會發現一些新穎的方式將它們整合到你的app中去!
定製一個視頻播放器的能力在iOS版本每次的發佈中一直有所進步。好比說,在iOS6以前,你不能在MPVolumeView中改變AirPlay的icon。
在iOS7當中,你能夠經過AirPlay,藍牙或是其餘的虛線機制瞭解是否有一個遠程的設備可用。瞭解它的話,就可讓你的app在恰當的時候作恰當的事,好比說,在沒有遠程設備的時候就不顯示AirPlay的icon。
如下是新增長到MPVolumeView的新屬性和推送
1
2
3
4
|
@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中如何使用這個新功能:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
|
@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。
iOS7以及Mavericks增長了iCloud Keychain來提供密碼,以及iCloud中一些敏感數據的同步。開發者能夠經過keychain中的kSecAttrSynchronizable key來遍歷dictionary對象。
因爲直接處理keychain比較難,封裝庫提供了一個簡單的處理keychain的方法。SSKeychain封裝庫多是最有名的的一個,做爲一種福利,如今它支持在iCloud同步。
如下代碼片斷顯示瞭如何使用SSKeychain:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
|
#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的好方法。
在app中使用webview有時會讓人很是沮喪,即便只是顯示少許的HTMLneirong ,webview也會消耗大量的內存。如今iOS7讓這些變得簡單了,你能夠從用少許代碼在HTML文件中建立一個NSAttributedString,好比:
1
2
3
4
|
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字符串,以下:
1
2
3
4
5
|
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是使用ASCII碼顯示二進制數據的一種流行方法。直到如今,開發者還不得不使用開源的工具來編碼解碼Base64的內容。
如今iOS7引入瞭如下四種新的NSData方法來操做Base64編碼的數據:
1
2
3
4
5
6
7
8
|
// 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。見如下的例子:
1
2
3
4
5
6
7
|
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或者更早之前的系統,你可使用如下兩個方法:
1
2
3
4
5
6
|
/* 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;
|
在iOS7以前,像Snapshot或是Facebook Poke這樣的app是使用一些很精巧的方法來檢測用戶是否有截圖。然而,iOS7提供一個嶄新的推送方法:UIApplicationUserDidTakeScreenshotNotification。只要像往常同樣訂閱便可知道何時截圖了。
注意:UIApplicationUserDidTakeScreenshotNotification 將會在截圖完成以後顯示。如今在截圖截取以前沒法獲得通知。但願蘋果會在iOS8當中增長UIApplicationUserWillTakeScreenshotNotification。
若是可讓app說話會不會很好呢?iOS7加入了兩個新類:AVSpeechSynthesizer 以及AVSpeechUtterance。這兩個類能夠給你的app發聲。頗有意思不是嗎?有多種語言可供選擇——Siri不會說的語言也有,好比說巴西葡萄牙語。
使用這兩個類給app提供語言合成的功能很是簡單。AVSpeechUtterance 表明你想說什麼,如何說。AVSpeechSynthesizer 用來發出這些聲音,見如下代碼片斷:
1
2
3
4
5
6
|
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 繼承自UIPanGestureRecognizer ,它可讓你從屏幕邊界便可檢測手勢。
使用新的手勢識別器很簡單,見如下:
1
2
3
|
UIScreenEdgePanGestureRecognizer *recognizer = [[UIScreenEdgePanGestureRecognizer alloc] initWithTarget:self action:@selector(handleScreenEdgeRecognizer:)];
recognizer.edges = UIRectEdgeLeft;
[self.view addGestureRecognizer:recognizer];
|
像Messages app同樣在滾動的時候可讓鍵盤消失是一種很是好的體驗。然而,將這種行爲整合到你的app很難。幸運的是,蘋果給UIScrollView添加了一個很好用的屬性keyboardDismissMode,這樣能夠方便不少。
如今僅僅只須要在Storyboard中改變一個簡單的屬性,或者增長一行代碼,你的app能夠和辦到和Messages app同樣的事情了。
這個屬性使用了新的UIScrollViewKeyboardDismissMode enum枚舉類型。這個enum枚舉類型可能的值以下:
1
2
3
4
|
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
|
如下是讓鍵盤能夠在滾動的時候消失須要設置的屬性:
iOS給Core Image增長了兩種人臉檢測功能:CIDetectorEyeBlink以及CIDetectorSmile。這也就是說你如今能夠在照片中檢測微笑以及眨眼。
如下是在app中使用它的方法:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
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!");
}
}
|
如今在iOS添加你本身的Twitter帳戶更加簡單了,如今你能夠給一個NSAttributedString增長連接了,而後當它被點擊的時候喚起一個定製的action。
首先,建立一個NSAttributedString而後增長給它增長一個NSLinkAttributeName 屬性,見如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
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方法,就像這樣:
1
2
3
4
5
6
7
8
9
|
- (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
}
|
UIAlertController.h
提示框按鈕的選擇
1
2
3
4
5
6
7
8
9
|
typedef NS_ENUM(NSInteger, UIAlertActionStyle) {
UIAlertActionStyleDefault = 0,
UIAlertActionStyleCancel,
UIAlertActionStyleDestructive
} NS_ENUM_AVAILABLE_IOS(8_0);
|
提示框的樣式
1
2
3
4
5
6
7
8
9
|
typedef NS_ENUM(NSInteger, UIAlertControllerStyle) {
UIAlertControllerStyleActionSheet = 0,
UIAlertControllerStyleAlert
} NS_ENUM_AVAILABLE_IOS(8_0);
NS_CLASS_AVAILABLE_IOS(8_0) @interface UIAlertAction : NSObject <NSCopying>
|
建立提示框按鈕
1
2
3
4
5
6
7
8
9
10
11
|
+ (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
|
建立提示框
1
|
+ (instancetype)alertControllerWithTitle:(NSString *)title message:(NSString *)message preferredStyle:(UIAlertControllerStyle)preferredStyle;
|
添加按鈕
1
2
3
|
- (void)addAction:(UIAlertAction *)action;
@property (nonatomic, readonly) NSArray *actions;
|
添加文本輸入框
1
2
3
4
5
6
7
8
9
|
- (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
2
3
4
5
6
7
8
9
10
11
|
// 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];
|
UIViewController.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
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
2
3
4
5
6
7
8
9
10
11
|
// 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
2
3
4
5
6
7
8
9
10
|
// 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];
|
地圖定位示例 :
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
|
// 導入定位框架
#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是爲了解決storyboard只能訂製一種屏幕樣式的問題,它再也不是具體的尺寸,而是抽象尺寸經過寬/高 的compact、any、regular 組成了九種組合包含了全部蘋果設備的尺寸。
iOS9系統發送的網絡請求將統一使用TLS 1.2 SSL。採用TLS 1.2 協議,目的是強制加強數據訪問安全,並且系統Foundation框架下的相關網絡請求,將再也不默認使用HTTP等不安全的網絡協議,而默認採用TLS 1.2。服務器所以須要更新,以解析相關數據。如不更新,可經過在 info.plist 中聲明,倒退回不安全的網絡請求。
什麼是SSL/TLS?跟HTTP和HTTPS有什麼關係?
跟往常同樣,先說結論:
1
|
HTTP + SSL/TLS + TCP = HTTPS
|
TLS 是 SSL 新的別稱。舉個例子:
「TLS1.0」之於「SSL3.1」,猶「公元2015」之於「民國104」,或者是「一千克」之於「一公斤」,或者是「半斤」之於「八兩」:稱呼不一樣,但意思相同。
SSL 3.0版本以後的迭代版本被從新命名爲TLS 1.0,也就是說:
1
|
TLS 1.0 = SSL 3.1
|
因此他們是一個東西,咱們日常也常常簡單見到 「SSL/TLS」 這種說法。經常使用的是下面這些:
1
2
3
4
5
6
7
8
9
|
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什麼事? 要理解這個,要看下一個公式:
1
|
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源碼以下所示:
上面是比較嚴謹的作法,指定了能訪問哪些特定的HTTP。固然也有暴力的作法: 完全倒退回不安全的HTTP網絡請求,能任意進行HTTP請求,好比你在開發一款瀏覽器App,或者你想偷懶,或者後臺想偷懶,或者公司不給你升級服務器。
若是不適配iOS9,就不能偷偷在後臺定位。不過蘋果將容許出現這種場景:
同一App中的多個location manager,一些只能在前臺定位,另外一些可在後臺定位,並可隨時開啓或者關閉特定location manager的後臺定位。
如何偷偷在後臺定位:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
|
// 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 配置以下:
對應的 Info.plist 的XML源碼是:
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
for
this
target.
for
architecture arm64
問題的緣由是:某些第三方庫還不支持bitcode。要否則是等待庫的開發者升級了此項功能咱們更新庫,要不就是把這個bitcode禁用。禁用Bitcode,方法見下圖:
iOS9以前,企業級分發十分方便:點擊App出現「信任按鈕」。
iOS9之後,企業級分發ipa包將遭到與Mac上dmg安裝包同樣的待遇。默認不能安裝,也再也不出現「信任按鈕」,必須讓用戶進行gif圖中的設置。
URL scheme通常使用的場景是應用程序有分享或跳其餘平臺受權的功能,分享或受權後再跳回來。在iOS8並無作過多限制,在iOS9中,若是使用URL scheme必須在"info.plist"中將你要在外部調用的URL scheme列爲白名單,不然不能使用。
canOpenURL: failed
for
URL :
"mqzone://qqapp"
- error:
"This app is not allowed to query for scheme mqzone"
具體的解決方案也是要在info.plist中設置 LSApplicationQueriesSchemes 類型爲數組,下面添加全部你用到的scheme
其中最關鍵的是如下部分:
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可能會出現「...」的狀況。
上面這兩張圖也能夠直觀的看出同一個界面,同一個label的變化。
因此爲了在界面顯示上不出錯,就算是固定長度的文字也仍是建議使用sizetofit 或者ios向上取整 ceilf() 或者提早計算。
1
2
|
CGSize size = [title sizeWithAttributes:@{NSFontAttributeName: [UIFont systemFontOfSize:14.0f]}];
CGSize adjustedSize = CGSizeMake(ceilf(size.width), ceilf(size.height));
|
雖然如今的iOS9已經推送正式版了,可是iOS9使用時仍是會感受到App比之前更加卡頓了,tableView拖動時卡頓顯示的最爲明顯。 而且以前遇到一個bug,本來好的項目用xcode7一編譯,tableView刷新出了問題 ,[tableView reloadData]無效,有一行cell明明改變了可是刷新不出來。 感受多是這個方法和某種新加的特性衝突了,猜想多是reloadData的操做被推遲到下一個RunLoop執行最終失效。
解決的方法是,註釋[tableView reloadData],改用局部刷新,問題竟然就解決了。
1
|
[self.tableView reloadSections:[NSIndexSet indexSetWithIndex:0] withRowAnimation:UITableViewRowAnimationNone];
|