oc常見誤區

一、同步請求能夠從因特網請求數據,一旦發送同步請求,程序將中止用戶交互,直至服務器返回數據完成,才能夠進行下一步操做,php

 

二、異步請求不會阻塞主線程,而會創建一個新的線程來操做,用戶發出異步請求後,依然能夠對UI進行操做,程序能夠繼續運行css

 

三、GET請求,將參數直接寫在訪問路徑上。操做簡單,不過容易被外界看到,安全性不高,地址最多255字節;html

 

四、POST請求,將參數放到body裏面。POST請求操做相對複雜,須要將參數和地址分開,不過安全性高,參數放在body裏面,不易被捕獲。java

 

查看源碼打印?android

001ios

一、     同步GET請求git

    //第一步,建立URL程序員

    NSURL*url = [NSURL URLWithString:@"http://api.hudong.com/iphonexml.do?type=focus-c"];github

    //第二步,經過URL建立網絡請求web

    NSURLRequest *request = [[NSURLRequest alloc]initWithURL:url cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:10];

    //NSURLRequest初始化方法第一個參數:請求訪問路徑,第二個參數:緩存協議,第三個參數:網絡請求超時時間(秒)

      其中緩存協議是個枚舉類型包含:

      NSURLRequestUseProtocolCachePolicy(基礎策略)

      NSURLRequestReloadIgnoringLocalCacheData(忽略本地緩存)

      NSURLRequestReturnCacheDataElseLoad(首先使用緩存,若是沒有本地緩存,才從原地址下載)

      NSURLRequestReturnCacheDataDontLoad(使用本地緩存,從不下載,若是本地沒有緩存,則請求失敗,此策略多用於離線操做)

      NSURLRequestReloadIgnoringLocalAndRemoteCacheData(無視任何緩存策略,不管是本地的仍是遠程的,老是從原地址從新下載)

 

      NSURLRequestReloadRevalidatingCacheData(若是本地緩存是有效的則不下載,其餘任何狀況都從原地址從新下載)

    //第三步,鏈接服務器

    NSData *received = [NSURLConnection sendSynchronousRequest:request returningResponse:nil error:nil];

    NSString *str = [[NSString alloc]initWithData:received encoding:NSUTF8StringEncoding];

    NSLog(@"%@",str);

二、同步POST請求

    //第一步,建立URL

    NSURL *url = [NSURL URLWithString:@"http://api.hudong.com/iphonexml.do"];

    //第二步,建立請求

    NSMutableURLRequest *request = [[NSMutableURLRequest alloc]initWithURL:url cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:10];

    [request setHTTPMethod:@"POST"];//設置請求方式爲POST,默認爲GET

    NSString *str = @"type=focus-c";//設置參數

    NSData *data = [str dataUsingEncoding:NSUTF8StringEncoding];

    [request setHTTPBody:data];

    //第三步,鏈接服務器

    NSData *received = [NSURLConnection sendSynchronousRequest:request returningResponse:nil error:nil];

    NSString *str1 = [[NSString alloc]initWithData:received encoding:NSUTF8StringEncoding];

    NSLog(@"%@",str1);

072

三、異步GET請求

    //第一步,建立url

    NSURL *url = [NSURL URLWithString:@"http://api.hudong.com/iphonexml.do?type=focus-c"];

    //第二步,建立請求

    NSURLRequest *request = [[NSURLRequest alloc]initWithURL:url cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:10];

    //第三步,鏈接服務器

    NSURLConnection *connection = [[NSURLConnection alloc]initWithRequest:request delegate:self];

085

四、異步POST請求

    //第一步,建立url

    NSURL *url = [NSURL URLWithString:@"http://api.hudong.com/iphonexml.do"];

    //第二步,建立請求

    NSMutableURLRequest *request = [[NSMutableURLRequest alloc]initWithURL:url cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:10];

    [request setHTTPMethod:@"POST"];

    NSString *str = @"type=focus-c";

    NSData *data = [str dataUsingEncoding:NSUTF8StringEncoding];

    [request setHTTPBody:data];

    //第三步,鏈接服務器

    NSURLConnection *connection = [[NSURLConnection alloc]initWithRequest:request delegate:self];

五、異步請求的代理方法

 

//接收到服務器迴應的時候調用此方法

- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response

{

    NSHTTPURLResponse *res = (NSHTTPURLResponse *)response;

    NSLog(@"%@",[res allHeaderFields]);

    self.receiveData = [NSMutableData data];

 

}

//接收到服務器傳輸數據的時候調用,此方法根據數據大小執行若干次

-(void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data

{

    [self.receiveData appendData:data];

}

//數據傳完以後調用此方法

-(void)connectionDidFinishLoading:(NSURLConnection *)connection

{

    NSString *receiveStr = [[NSString alloc]initWithData:self.receiveData encoding:NSUTF8StringEncoding];

    NSLog(@"%@",receiveStr);

}

//網絡請求過程當中,出現任何錯誤(斷網,鏈接超時等)會進入此方法

-(void)connection:(NSURLConnection *)connection

didFailWithError:(NSError *)error

{

    NSLog(@"%@",[error localizedDescription]); }

從表面的意思看get 和 post的區別get就是獲取數據,post就是發送數據。這個是誤區。其實二者均可以的,在IOS向服務器發送請求裏面能夠帶參數。

 

那麼這些誤區是怎麼出現的呢?先看看一下對http的解釋

 

通常在瀏覽器中輸入網址訪問資源都是經過GET方式;在FORM提交中,能夠經過Method指定提交方式爲GET或者POST,默認爲GET提交 

Http定義了與服務器交互的不一樣方法,最基本的方法有4種,分別是GET,POST,PUT,DELETE 

URL全稱是資源描述符,咱們能夠這樣認爲:一個URL地址,它用於描述一個網絡上的資源,而HTTP中的GET,POST,PUT,DELETE就對應着對這個資源的查 ,改 ,增 ,刪 4個操做。到這裏,你們應該有個大概的瞭解了,GET通常用於獲取/查詢 資源信息,而POST通常用於更新 資源信息(我的認爲這是GET和POST的本質區別,也是協議設計者的本意,其它區別都是具體表現形式的差別 )。

 

再進一步瞭解下他們兩個的區別:

 

1. GET使用URL或Cookie傳參。而POST將數據放在BODY中。

 

2. GET的URL會有長度上的限制,則POST的數據則能夠很是大。

 

3. POST比GET安全,由於數據在地址欄上不可見。

 

這些也是有點誤區的,就像同步請求必定的慢嗎?

 

GET和POST與數據如何傳遞沒有關係?

 

GET和POST是由HTTP協議定義的。在HTTP協議中,Method和Data(URL, Body, Header)是正交的兩個概念,也就是說,使用哪一個Method與應用層的數據如何傳輸是沒有相互關係的。

 

HTTP沒有要求,若是Method是POST數據就要放在BODY中。也沒有要求,若是Method是GET,數據(參數)就必定要放在URL中而不能放在BODY中。

 

那麼,網上流傳甚廣的這個說法是從何而來的呢?我在HTML標準中,找到了類似的描述。這和網上流傳的說法一致。可是這只是HTML標準對HTTP協議的用法的約定。怎麼能當成GET和POST的區別呢?

 

並且,現代的Web Server都是支持GET中包含BODY這樣的請求。雖然這種請求不可能從瀏覽器發出,可是如今的Web Server又不是隻給瀏覽器用,已經徹底地超出了HTML服務器的範疇了。

 

HTTP協議對GET和POST都沒有對長度的限制?

 

HTTP協議明確地指出了,HTTP頭和Body都沒有長度的要求。而對於URL長度上的限制,有兩方面的緣由形成:

1. 瀏覽器。聽說早期的瀏覽器會對URL長度作限制。聽說IE對URL長度會限制在2048個字符內(流傳很廣,並且無數同事都表示認同)。但我本身試了一下,我構造了90K的URL經過IE9訪問live.com,是正常的。網上的東西,哪怕是Wikipedia上的,也不能信。

 

2. 服務器。URL長了,對服務器處理也是一種負擔。本來一個會話就沒有多少數據,如今若是有人惡意地構造幾個幾M大小的URL,並不停地訪問你的服務器。服務器的最大併發數顯然會降低。另外一種攻擊方式是,把告訴服務器Content-Length是一個很大的數,而後只給服務器發一點兒數據,嘿嘿,服務器你就傻等着去吧。哪怕你有超時設置,這種故意的次次訪問超時也能讓服務器吃不了兜着走。有鑑於此,多數服務器出於安全啦、穩定啦方面的考慮,會給URL長度加限制。可是這個限制是針對全部HTTP請求的,與GET、POST沒有關係。

 

這個貌似聽着對點吧。

 

3.對於安全不安全講。

 

get:

.所謂安全的意味着該操做用於獲取信息而非修改信息。換句話說,GET請求通常不該產生反作用。就是說,它僅僅是獲取資源信息,就像數據庫查詢同樣,不會修改,增長數據,不會影響資源的狀態。 

* 注意:這裏安全的含義僅僅是指是非修改信息。

 

POST的安全性要比GET的安全性高。注意:這裏所說的安全性和上面GET提到的「安全」不是同個概念。上面「安全」的含義僅僅是不做數據修改,而這裏安全的含義是真正的Security的含義,好比:經過GET提交數據,用戶名和密碼將明文出如今URL上,由於(1)登陸頁面有可能被瀏覽器緩存, (2)其餘人查看瀏覽器的歷史紀錄,那麼別人就能夠拿到你的帳號和密碼了,除此以外,使用GET提交數據還可能會形成Cross-site request forgery攻擊 .

 

看出來區別了吧

 

單例建立:

建立一個單例不少辦法。我先列舉一個蘋果官方文檔中的寫法。

 

static AccountManager *DefaultManager = nil;  

+ (AccountManager *)defaultManager {  

  1. if (!DefaultManager) DefaultManager = [[self allocWithZone:NULL] init];  
  2. return DefaultManager;  
  3. }  


固然,在iOS4以後有了另一種寫法:

+ (AccountManager *)sharedManager  

{  

        static AccountManager *sharedAccountManagerInstance = nil;  

        static dispatch_once_t predicate;  

        dispatch_once(&predicate, ^{  

                sharedAccountManagerInstance = [[self alloc] init];   

        });  

    return sharedAccountManagerInstance;  

}  

該寫法來自 objcolumnist,文中提到,該寫法具備如下幾個特性:

1. 線程安全。

2. 知足靜態分析器的要求。

3. 兼容了ARC

 

http://duxinfeng.com/2015/07/14/iOS%E5%BC%80%E6%BA%90App%E6%95%B4%E7%90%86/

 

使用支付寶進行一個完整的支付功能,大體有如下步驟:

  • 與支付寶簽約,得到商戶IDpartner)和帳號IDseller
  • 下載相應的公鑰私鑰文件(加密簽名用)
  • 下載支付寶SDK
  • 生成訂單信息
  • 調用支付寶客戶端,由支付寶客戶端跟支付寶安全服務器打交道
  • 支付完畢後返回支付結果給商戶客戶端和服務器

支付寶提供了Demo讓開發人員快速瞭解支付的接入流程:http://club.alipay.com/thread.php?fid=703,遇到技術上的問題也以到論壇提問

 

假設簽約之類工做已經完成,咱們開幹

 

要想集成支付功能,依賴如下文件夾的庫文件(把這3個添加到你的客戶端中)

 

 

 

接口調用步驟

1.封裝訂單模型

AlixPayOrder *order = [[AlixPayOrder alloc] init];

// 生成訂單描述

NSString *orderSpec = [order description];

 

2.簽名

id<DataSigner> signer = CreateRSADataSigner(@「私鑰key」);

// 傳入訂單描述 進行 簽名

NSString *signedString = [signer signString:orderSpec];

 

 

3.生成訂單字符串

NSString *orderString = [NSString stringWithFormat:@"%@&sign=\"%@\"&sign_type=\"%@\"",

                         orderSpec, signedString, @"RSA"];

 

4.調用支付接口

AlixPay * alixpay = [AlixPay shared];

// appScheme:商戶本身的協議頭

int ret = [alixpay pay:orderString applicationScheme:appScheme];

 

如今隨着移動開發的快速發展,愈來愈多的應用要求在線支付功能。最近作了一個關於支付寶支付功能的應用,在使用支付寶的過程當中,遇到一些沒必要要的彎路,所以,寫了這篇文章總結一下關於ios開發如何使用支付寶。

正文

首先,咱們須要支付寶的功能,應該去支付寶的開發平臺,下載sdk以及demo。地址:點擊進入下載頁面

第一步、將須要的文件,靜態庫等拖入工程中,這裏有:includelibsUtilitieslibcrypto.alibssl.a文件。

如圖:

 

上面就是咱們所要獲得的結果。

第二步、設置Head Search Paths 和 Library Search Paths

targets->Build Setting ->Search Paths->Head Search Paths Library Search Paths

切記:Head Search Paths  Library Search Paths的路徑必定要根據這個地址能找到對應的頭文件。否則設置總會有這個錯誤(我就在這兒耗了不少時間),如圖:

#include <openssl/rsa.h> 'openssl/rsa.h' file not found

 

 

下面是我設置的正確路徑,如圖:

 

好的,這裏設置已經完成了,編譯成功。

第三步、設置partnersellerRSA private keyRSA public key

我這裏和官方demo同樣都是設置在-info文件中,固然,你也能夠自行決定放在其餘地方。

如圖:

 

這裏的參數來自其餘地方。。

第四步、支付成功後,回到應用程序中。

注意代碼中有這句代碼:

  1. //應用註冊scheme,AlixPayDemo-Info.plist定義URL types,用於安全支付成功後從新喚起商戶應用  
  2. NSString *appScheme = @"paytest";  


因此,咱們還須要設置回調的標示。

一樣在-info文件中,添加個節點。如圖:

 

注意:上面的item0的值就是appScheme

 

 

 

 

 

1)官方下載ShareSDK iOS 2.8.8,地址:http://sharesdk.cn/

 

2)根據實際狀況,引入相關的庫,參考官方文檔

 

3)在項目的AppDelegate中通常狀況下有三個操做,第一是註冊ShareSDK,第二是註冊各個平臺的帳號,第三是關於微信等應用的回調處理。

  1. //  
  2. //  AppDelegate.m  
  3. //  ShareSDKTest  
  4. //  
  5. //  Created by wangdalei on 14-6-23.  
  6. //  Copyright (c) 2014 王大雷. All rights reserved.  
  7. //  
  8. #import "AppDelegate.h"  
  9. #import "RootViewController.h"  
  10. #import <ShareSDK/ShareSDK.h>  
  11. #import "WeiboApi.h"  
  12. #import <TencentOpenAPI/QQApiInterface.h>  
  13. #import <TencentOpenAPI/TencentOAuth.h>  
  14. #import "WXApi.h"  
  15. #import <TencentOpenAPI/QQApiInterface.h>  
  16. #import <TencentOpenAPI/TencentOAuth.h>  
  17. @implementation AppDelegate  
  18. @synthesize rootVC;  
  19. - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {  
  20. self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];  
  21. if (self.rootVC==nil) {  
  22. self.rootVC = [[RootViewController alloc]initWithNibName:@"RootViewController" bundle:nil];  
  23. }  
  24. UINavigationController *rootNav = [[UINavigationController alloc]initWithRootViewController:self.rootVC];  
  25. self.window.rootViewController = rootNav;  
  26. self.window.backgroundColor = [UIColor whiteColor];  
  27. [self.window makeKeyAndVisible];  
  28. <span style="color:#ff0000;">[ShareSDK registerApp:@"1a2e7ab5fb6c"];</span>  
  29. <span style="color:#3366ff;"> //添加新浪微博應用 註冊網址 http://open.weibo.com  wdl@pmmq.com 此處須要替換成本身應用的  
  30. [ShareSDK connectSinaWeiboWithAppKey:@"3201194191"  
  31. appSecret:@"0334252914651e8f76bad63337b3b78f"  
  32. redirectUri:@"http://appgo.cn"];  
  33. //添加騰訊微博應用 註冊網址 http://dev.t.qq.com wdl@pmmq.com 此處須要替換成本身應用的  
  34. [ShareSDK connectTencentWeiboWithAppKey:@"801307650"  
  35. appSecret:@"ae36f4ee3946e1cbb98d6965b0b2ff5c"  
  36. redirectUri:@"http://www.sharesdk.cn"  
  37. wbApiCls:[WeiboApi class]];  
  38. //添加QQ空間應用 註冊網址  http://connect.qq.com/intro/login/ wdl@pmmq.com 此處須要替換成本身應用的  
  39. [ShareSDK connectQZoneWithAppKey:@"100371282"  
  40. appSecret:@"aed9b0303e3ed1e27bae87c33761161d"  
  41. qqApiInterfaceCls:[QQApiInterface class]  
  42. tencentOAuthCls:[TencentOAuth class]];  
  43. //此參數爲申請的微信AppID wdl@pmmq.com 此處須要替換成本身應用的  
  44. [ShareSDK connectWeChatWithAppId:@"wx4868b35061f87885" wechatCls:[WXApi class]];  
  45. //添加QQ應用 該參數填入申請的QQ AppId wdl@pmmq.com 此處須要替換成本身應用的  
  46. [ShareSDK connectQQWithQZoneAppKey:@"100371282"  
  47. qqApiInterfaceCls:[QQApiInterface class]  
  48. tencentOAuthCls:[TencentOAuth class]];</span>  
  49. return YES;  
  50. }  
  51. - (void)applicationWillResignActive:(UIApplication *)application {  
  52. // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.  
  53. // Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game.  
  54. }  
  55. - (void)applicationDidEnterBackground:(UIApplication *)application {  
  56. // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.   
  57. // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.  
  58. }  
  59. - (void)applicationWillEnterForeground:(UIApplication *)application {  
  60. // Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background.  
  61. }  
  62. - (void)applicationDidBecomeActive:(UIApplication *)application {  
  63. // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.  
  64. }  
  65. - (void)applicationWillTerminate:(UIApplication *)application {  
  66. // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.  
  67. }  
  68. <span style="color:#ff6600;">#pragma mark - WX回調  
  69. - (BOOL)application:(UIApplication *)application handleOpenURL:(NSURL *)url {  
  70. return [ShareSDK handleOpenURL:url wxDelegate:self];  
  71. }  
  72. - (BOOL)application:(UIApplication *)application openURL:(NSURL *)url sourceApplication:(NSString *)sourceApplication annotation:(id)annotation {  
  73. return [ShareSDK handleOpenURL:url sourceApplication:sourceApplication annotation:annotation wxDelegate:self];  
  74. }  
  75. #pragma mark - WXApiDelegate  
  76. /*! @brief 收到一個來自微信的請求,第三方應用程序處理完後調用sendResp向微信發送結果 
  77. 收到一個來自微信的請求,異步處理完成後必須調用sendResp發送處理結果給微信。 
  78. 可能收到的請求有GetMessageFromWXReqShowMessageFromWXReq等。 
  79. * @param req 具體請求內容,是自動釋放的 
  80. */  
  81. -(void) onReq:(BaseReq*)req{  
  82. }  
  83. /*! @brief 發送一個sendReq後,收到微信的迴應 
  84. 收到一個來自微信的處理結果。調用一次sendReq後會收到onResp 
  85. 可能收到的處理結果有SendMessageToWXRespSendAuthResp等。 
  86. * @param resp具體的迴應內容,是自動釋放的 
  87. */  
  88. -(void) onResp:(BaseResp*)resp{  
  89. }  
  90. </span>  
  91. @end  

 

4)信息分享。

  1. -(IBAction)share:(id)sender{  
  2. NSString *imagePath = [[NSBundle mainBundle] pathForResource:@"card"  ofType:@"png"];  
  3. //構造分享內容  
  4. id<ISSContent> publishContent = [ShareSDK content:@"分享內容測試"  
  5. defaultContent:@"默認分享內容測試,沒內容時顯示"  
  6. image:[ShareSDK imageWithPath:imagePath]  
  7. title:@"pmmq"  
  8. url:@"http://www.sharesdk.cn"  
  9. description:@"這是一條測試信息"  
  10. mediaType:SSPublishContentMediaTypeNews];  
  11. [ShareSDK showShareActionSheet:nil  
  12. shareList:nil  
  13. content:publishContent  
  14. statusBarTips:YES  
  15. authOptions:nil  
  16. shareOptions: nil  
  17. result:^(ShareType type, SSResponseState state, id<ISSPlatformShareInfo> statusInfo, id<ICMErrorInfo> error, BOOL end) {  
  18. if (state == SSResponseStateSuccess)  
  19. {  
  20. NSLog(@"分享成功");  
  21. }  
  22. else if (state == SSResponseStateFail)  
  23. {  
  24. NSLog(@"分享失敗");  
  25. }  
  26. }];  
  27. }  


5)登陸、登出、獲取受權信息、關注制定微博

  1. //  
  2. //  LoginViewController.m  
  3. //  ShareSDKTest  
  4. //  
  5. //  Created by wangdalei on 14-6-23.  
  6. //  Copyright (c) 2014 王大雷. All rights reserved.  
  7. //  
  8. #import "LoginViewController.h"  
  9. #import <ShareSDK/ShareSDK.h>  
  10. @interface LoginViewController ()  
  11. -(IBAction)loginWithSina:(id)sender;  
  12. -(IBAction)loginWithQQ:(id)sender;  
  13. -(IBAction)loginoutWithSina:(id)sender;  
  14. -(IBAction)loginoutWithQQ:(id)sender;  
  15. -(IBAction)guanzhuUs:(id)sender;  
  16. -(void)reloadStateWithType:(ShareType)type;  
  17. @end  
  18. @implementation LoginViewController  
  19. - (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil {  
  20. self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];  
  21. if (self) {  
  22. }  
  23. return self;  
  24. }  
  25. - (void)viewDidLoad {  
  26. [super viewDidLoad];  
  27. }  
  28. - (void)didReceiveMemoryWarning {  
  29. [super didReceiveMemoryWarning];  
  30. }  
  31. - (IBAction)loginWithSina:(id)sender {  
  32. [ShareSDK getUserInfoWithType:ShareTypeSinaWeibo authOptions:nil result:^(BOOL result, id<ISSPlatformUser> userInfo, id<ICMErrorInfo> error) {  
  33. NSLog(@"%d",result);  
  34. if (result) {  
  35. //成功登陸後,判斷該用戶的ID是否在本身的數據庫中。  
  36. //若是有直接登陸,沒有就將該用戶的ID和相關資料在數據庫中建立新用戶。  
  37. [self reloadStateWithType:ShareTypeSinaWeibo];  
  38. }  
  39. }];  
  40. }  
  41. -(IBAction)loginWithQQ:(id)sender{  
  42. [ShareSDK getUserInfoWithType:ShareTypeQQSpace authOptions:nil result:^(BOOL result, id<ISSPlatformUser> userInfo, id<ICMErrorInfo> error) {  
  43. NSLog(@"%d",result);  
  44. if (result) {  
  45. //成功登陸後,判斷該用戶的ID是否在本身的數據庫中。  
  46. //若是有直接登陸,沒有就將該用戶的ID和相關資料在數據庫中建立新用戶。  
  47. [self reloadStateWithType:ShareTypeQQSpace];  
  48. }  
  49. }];  
  50. }  
  51. -(IBAction)loginoutWithSina:(id)sender{  
  52. [ShareSDK cancelAuthWithType:ShareTypeSinaWeibo];  
  53. [self reloadStateWithType:ShareTypeSinaWeibo];  
  54. }  
  55. -(IBAction)loginoutWithQQ:(id)sender{  
  56. [ShareSDK cancelAuthWithType:ShareTypeQQSpace];  
  57. [self reloadStateWithType:ShareTypeQQSpace];  
  58. }  
  59. -(void)reloadStateWithType:(ShareType)type{  
  60. //現實受權信息,包括受權ID、受權有效期等。  
  61. //此處能夠在用戶進入應用的時候直接調用,如受權信息不爲空且不過時可幫用戶自動實現登陸。  
  62. id<ISSPlatformCredential> credential = [ShareSDK getCredentialWithType:type];  
  63. UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:NSLocalizedString(@"TEXT_TIPS", @"提示")  
  64. message:[NSString stringWithFormat:  
  65. @"uid = %@\ntoken = %@\nsecret = %@\n expired = %@\nextInfo = %@",  
  66. [credential uid],  
  67. [credential token],  
  68. [credential secret],  
  69. [credential expired],  
  70. [credential extInfo]]  
  71. delegate:nil  
  72. cancelButtonTitle:NSLocalizedString(@"TEXT_KNOW", @"知道了")  
  73. otherButtonTitles:nil];  
  74. [alertView show];  
  75. }  
  76. //關注用戶  
  77. -(IBAction)guanzhuUs:(id)sender{  
  78. [ShareSDK followUserWithType:ShareTypeSinaWeibo         //平臺類型  
  79. field:@"ShareSDK"                //關注用戶的名稱或ID  
  80. fieldType:SSUserFieldTypeName        //字段類型,用於指定第二個參數是名稱仍是ID  
  81. authOptions:nil                        //受權選項  
  82. viewDelegate:nil                        //受權視圖委託  
  83. result:^(SSResponseState state, id<ISSPlatformUser> userInfo, id<ICMErrorInfo> error) {  
  84. if (state == SSResponseStateSuccess) {  
  85. NSLog(@"關注成功");  
  86. } else if (state == SSResponseStateFail) {  
  87. NSLog(@"%@", [NSString stringWithFormat:@"關注失敗:%@", error.errorDescription]);  
  88. }  
  89. }];  
  90. }  
  91. @end  


5)你可能會看到一些應用須要第三方登陸的,一種是彈出webView加載的新浪微博或者qq的網頁受權,還有一種是跳轉到本地的已經安裝的新浪微博應用或者qq應用進行受權。第二種受權方式較SSO受權,體驗會比較好一些,由於不須要用戶輸入新浪微博或QQ的用戶名與密碼。

第二種受權方式須要在plist中配置SchemeSSO默認是打開的不須要配置。在AppDelegate中實現回調。

 

 

6)測試DEMO截圖:

 

 

 

 

AFNetworking是一個討人喜歡的網絡庫,適用於iOS以及Mac OS X. 它構建於在NSURLConnectionNSOperation以及其餘熟悉的Foundation技術之上它擁有良好的架構,豐富的api,以及模塊化構建方式,使得使用起來很是輕鬆.例如,他能夠使用很輕鬆的方式從一個url來獲得json數據:

1

NSURL *url = [NSURL URLWithString:@"http://api.twitter.com/1/statuses/public_timeline.json"];

2

NSURLRequest *request = [NSURLRequest requestWithURL:url];

3

AFJSONRequestOperation *operation = [AFJSONRequestOperation JSONRequestOperationWithRequest:request success:^(NSURLRequest *request, NSHTTPURLResponse *response, id JSON) {

4

    NSLog(@"Public Timeline: %@", JSON);

5

} failure:nil];

6

[operation start];

綜述

CORE:

AFURLConnectionOperation:一個 NSOperation 實現了NSURLConnection 的代理方法.

HTTP Requests:

AFHTTPRequestOperation:AFURLConnectionOperation的子類,request使用的協議爲HTTPHTTPS,它壓縮了用於決定request是否成功的狀態碼和內容類型.

AFJSONRequestOperation:AFHTTPRequestOperation的一個子類,用於下載和處理jason response數據.

AFXMLRequestOperation:AFHTTPRequestOperation的一個子類,用於下載和處理xml response數據.

AFPropertyListRequestOperation:AFHTTPRequestOperation的一個子類,用於下載和處理property list response數據.

HTTP CLIENT:

AFHTTPClient:捕獲一個基於http協議的網絡應用程序的公共交流模式.包含:

  • 使用基本的url相關路徑來只作request
  • request自動添加設置http headers.
  • 使用http 基礎證書或者OAuth來驗證request
  • 爲由client製做的requests管理一個NSOperationQueue
  • NSDictionary生成一個查詢字符串或http bodies.
  • request中構建多部件
  • 自動的解析http response數據爲相應的表現數據
  • 在網絡可達性測試用監控和響應變化.

IMAGES

AFImageRequestOperation:一個AFHTTPRequestOperation的子類,用於下載和處理圖片.

UIImageView+AFNetworking:添加一些方法到UIImageView,爲了從一個URL中異步加載遠程圖片

 

如何經過URL獲取json數據

第一種,利用AFJSONRequestOperation,官方網站上給的例子:

  

[objc] view plaincopy

  1. NSString *str=[NSString stringWithFormat:@"https://alpha-api.app.net/stream/0/posts/stream/global"];  
  2. NSURL *url = [NSURL URLWithString:[str stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]];  
  3. NSURLRequest *request = [NSURLRequest requestWithURL:url];  
  4. //    URL獲取json數據  
  5. AFJSONRequestOperation *operation1 = [AFJSONRequestOperation JSONRequestOperationWithRequest:request success:^(NSURLRequest *request, NSHTTPURLResponse *response, NSDictionary* JSON) {  
  6. NSLog(@"獲取到的數據爲:%@",JSON);  
  7. } failure:^(NSURLRequest *request, NSHTTPURLResponse *response, NSError *error, id data) {  
  8. NSLog(@"發生錯誤!%@",error);  
  9. }];  
  10. [operation1 start];  

 

第二種方法,利用AFHTTPRequestOperation 先獲取到字符串形式的數據,而後轉換成json格式,將NSString格式的數據轉換成json數據,利用IOS5自帶的json解析方法:

 

[objc] view plaincopy

  1. NSString *str=[NSString stringWithFormat:@"https://alpha-api.app.net/stream/0/posts/stream/global"];  
  2. NSURL *url = [NSURL URLWithString:[str stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]];  
  3. NSURLRequest *request = [NSURLRequest requestWithURL:url];  
  4. AFHTTPRequestOperation *operation = [[AFHTTPRequestOperation alloc]initWithRequest:request];  
  5. [operation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, idresponseObject) {  
  6. NSString *html = operation.responseString;  
  7. NSData* data=[html dataUsingEncoding:NSUTF8StringEncoding];  
  8. id dict=[NSJSONSerialization  JSONObjectWithData:data options:0 error:nil];  
  9. NSLog(@"獲取到的數據爲:%@",dict);  
  10. }failure:^(AFHTTPRequestOperation *operation, NSError *error) {  
  11. NSLog(@"發生錯誤!%@",error);  
  12. }];  
  13. NSOperationQueue *queue = [[NSOperationQueue alloc] init];  
  14. [queue addOperation:operation];  

若是發生Error Domain=NSURLErrorDomain Code=-1000 "bad URL" UserInfo=0x14defc80 {NSUnderlyingError=0x14deea10 "bad URL", NSLocalizedDescription=bad URL這個錯誤,請檢查URL編碼格式。有沒有進行stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding

 

如何經過URL獲取圖片

異步獲取圖片,經過隊列實現,並且圖片會有緩存,在下次請求相同的連接時,系統會自動調用緩存,而不從網上請求數據。

[objc] view plaincopy

  1. UIImageView *imageView = [[UIImageView alloc] initWithFrame:CGRectMake(0.0f, 100.0f, 100.0f, 100.0f)];      [imageView setImageWithURL:[NSURL URLWithString:@"http://i.imgur.com/r4uwx.jpg"]placeholderImage:[UIImage imageNamed:@"placeholder-avatar"]];      [self.view addSubview:imageView];  
  2. 上面的方法是官方提供的,還有一種方法,  
  3. NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"http://www.scott-sherwood.com/wp-content/uploads/2013/01/scene.png"]];  
  4. AFImageRequestOperation *operation = [AFImageRequestOperation imageRequestOperationWithRequest:request imageProcessingBlock:nil success:^(NSURLRequest *request, NSHTTPURLResponse*response, UIImage *image) {  
  5. self.backgroundImageView.image = image;  
  6. } failure:^(NSURLRequest *request, NSHTTPURLResponse *response, NSError *error) {  
  7. NSLog(@"Error %@",error);  
  8. }];  
  9. [operation start];  

 

若是使用第一種URLWithString:  placeholderImage:會有更多的細節處理,其實實現仍是經過AFImageRequestOperation處理,能夠點擊URLWithString:  placeholderImage:方法進去看一下就一目瞭然了。因此我以爲仍是用第一種好。

 

如何經過URL獲取plist文件

經過url獲取plist文件的內容,用的不多,這個方法在官方提供的方法裏面沒有

  

[objc] view plaincopy

  1. NSString *weatherUrl = @"http://www.calinks.com.cn/buick/kls/Buickhousekeeper.plist";  
  2. NSURL *url = [NSURL URLWithString:[weatherUrl stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]];  
  3. NSURLRequest *request = [NSURLRequest requestWithURL:url];  
  4. [AFPropertyListRequestOperation addAcceptableContentTypes:[NSSet setWithObject:@"text/plain"]];  
  5. AFPropertyListRequestOperation *operation = [AFPropertyListRequestOperation propertyListRequestOperationWithRequest:request success:^(NSURLRequest *request,NSHTTPURLResponse *response, id propertyList) {  
  6. NSLog(@"%@",(NSDictionary *)propertyList);  
  7. }failure:^(NSURLRequest *request, NSHTTPURLResponse *response, NSError *error, idpropertyList) {  
  8. NSLog(@"%@",error);  
  9. }];  
  10. [operation start];  

如何經過URL獲取XML數據

xml解析使用AFXMLRequestOperation,須要實現蘋果自帶的NSXMLParserDelegate委託方法,XML中有一些不須要的協議格式內容,因此就不能像json那樣解析,還得實現委託。我以前有想過可否全部的XML連接用一個類處理,並且跟服務端作了溝通,結果很不方便,效果很差。XML大多標籤不一樣,格式也不固定,因此就有問題,使用json就要方便的多。

第一步;在.h文件中加入委託NSXMLParserDelegate

第二步;在.m文件方法中加入代碼

    

[objc] view plaincopy

  1. NSURL *url = [NSURL URLWithString:@"http://113.106.90.22:5244/sshopinfo"];  
  2. NSURLRequest *request = [NSURLRequest requestWithURL:url];  
  3. AFXMLRequestOperation *operation =  
  4. [AFXMLRequestOperation XMLParserRequestOperationWithRequest:request success:^(NSURLRequest*request, NSHTTPURLResponse *response, NSXMLParser *XMLParser) {  
  5. XMLParser.delegate = self;  
  6. [XMLParser setShouldProcessNamespaces:YES];  
  7. [XMLParser parse];  
  8. }failure:^(NSURLRequest *request, NSHTTPURLResponse *response, NSError *error, NSXMLParser*XMLParser) {  
  9. NSLog(@"%@",error);  
  10. }];  
  11. [operation start];  

 

第三步;在.m文件中實現委託方法

    //在文檔開始的時候觸發

-

[objc] view plaincopy

  1. (void)parserDidStartDocument:(NSXMLParser *)parser{  
  2. NSLog(@"解析開始!");  
  3. }  
  4. //解析起始標記  
  5. - (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary*)attributeDict{  
  6. NSLog(@"標記:%@",elementName);  
  7. }  
  8. //解析文本節點  
  9. - (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string{  
  10. NSLog(@"值:%@",string);  
  11. }  
  12. //解析結束標記  
  13. - (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName{  
  14. NSLog(@"結束標記:%@",elementName);  
  15. }  
  16. //文檔結束時觸發  
  17. -(void) parserDidEndDocument:(NSXMLParser *)parser{  
  18. NSLog(@"解析結束!");  
  19. }  

 

運行的結果:

如何使用AFHTTPClient進行web service操做

[objc] view plaincopy

  1. AFHTTPClient處理GET  POST請求.作網頁的朋友們這個方法用的比較多。在要常常調用某個請求時,能夠封裝,節省資源。  
  2. BaseURLString = @"http://www.raywenderlich.com/downloads/weather_sample/";  
  3. NSURL *baseURL = [NSURL URLWithString:[NSString stringWithFormat:BaseURLString]];  
  4. NSDictionary *parameters = [NSDictionary dictionaryWithObject:@"json" forKey:@"format"];  
  5. AFHTTPClient *client = [[AFHTTPClient alloc] initWithBaseURL:baseURL];  
  6. [client registerHTTPOperationClass:[AFJSONRequestOperation class]];  
  7. [client setDefaultHeader:@"Accept" value:@"text/html"];  
  8. [client postPath:@"weather.php" parameters:parameters success:^(AFHTTPRequestOperation*operation, id responseObject) {  
  9. NSString* newStr = [[NSString alloc] initWithData:responseObjectencoding:NSUTF8StringEncoding];  
  10. NSLog(@"POST請求:%@",newStr);  
  11. }failure:^(AFHTTPRequestOperation *operation, NSError *error) {  
  12. NSLog(@"%@",error);  
  13. }];  
  14. [client getPath:@"weather.php" parameters:parameters success:^(AFHTTPRequestOperation*operation, id responseObject) {  
  15. NSString* newStr = [[NSString alloc] initWithData:responseObjectencoding:NSUTF8StringEncoding];  
  16. NSLog(@"GET請求:%@",newStr);  
  17. }failure:^(AFHTTPRequestOperation *operation, NSError *error) {  
  18. NSLog(@"%@",error);  
  19. }];  

 

運行結果:

 

若是須要顯示網絡活動指示器,能夠用下面方法:

[objc] view plaincopy

  1. [AFNetworkActivityIndicatorManager sharedManager].enabled = YES;  

FILE UPLOAD WITH PROGRESS CALLBACK

01

NSURL *url = [NSURL URLWithString:@"http://api-base-url.com"];

02

AFHTTPClient *httpClient = [[AFHTTPClient alloc] initWithBaseURL:url];

03

NSData *imageData = UIImageJPEGRepresentation([UIImage imageNamed:@"avatar.jpg"], 0.5);

04

NSMutableURLRequest *request = [httpClient multipartFormRequestWithMethod:@"POST" path:@"/upload" parameters:nil constructingBodyWithBlock: ^(id <AFMultipartFormData>formData) {

05

    [formData appendPartWithFileData:imageData name:@"avatar" fileName:@"avatar.jpg" mimeType:@"image/jpeg"];

06

}];

07

 

08

AFHTTPRequestOperation *operation = [[[AFHTTPRequestOperation alloc] initWithRequest:request] autorelease];

09

[operation setUploadProgressBlock:^(NSInteger bytesWritten, long long totalBytesWritten, long long totalBytesExpectedToWrite) {

10

    NSLog(@"Sent %lld of %lld bytes", totalBytesWritten, totalBytesExpectedToWrite);

11

}];

12

[operation start];

STREAMING REQUEST

1

NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"http://localhost:8080/encode"]];

2

 

3

AFHTTPRequestOperation *operation = [[[AFHTTPRequestOperation alloc] initWithRequest:request] autorelease];

4

operation.inputStream = [NSInputStream inputStreamWithFileAtPath:[[NSBundle mainBundle] pathForResource:@"large-image" ofType:@"tiff"]];

5

operation.outputStream = [NSOutputStream outputStreamToMemory];

6

[operation start];

 

 

 

CoreData

1.  經常使用類和方法  ( 注意須要導入  coredata  框架  )

 

表結構:NSEntityDescription

表記錄:NSManagedObject 數據庫存放方式:NSPersistentStoreCoordinator(持久化存儲協調者數據庫操做:NSManagedObjectContext(被管理的對象上下文)

 

2. xcode  圖形管理

 

2. 3.

4.

 

 

 

 

2. 操做數據庫

 

 

.鏈接數據庫

  1. 首先須要建立一個操做數據庫的上下文。NSManagedObjectContext
  2. 操做數據庫的上下文須要設置一個調度者屬性,這個調度者是用來將圖形化 
    創建的模型和數據庫聯繫起來。
  3. 給調度者添加一個須要聯繫的數據庫。

.添加,更新,刪除

添加:

1. 新建實體 INST (插入) 2. 設置實體的屬性

3. 保存上下文

更新:

1. 判斷是否已有如出一轍的模型 2. 設置實體屬性

3. 保存上下文

刪除

.查詢

1.使用 NSFetchedResultsController 控制器

2.1 當操做數據上下文的內容改變的時候,會自動調用抓取結果控制器的代理方 法

3.

注意:必定要執行抓取請求,返回的數據在 sections ,這個數組中裝的都是遵 守 NSFetchedResultsSectionInfo 這個協議的對象。經過

numberOfObjects 就能獲取一組有多少數據對象了。

 

第一部分coredata的用法

先創建一個使用use coredata的工程,

 

在。xcdatamodeld文件中創建表格併爲表格添加屬性

 

 

爲表格添加關係,

下一步生成表格model

 

 

其中生成的modelUserDepartment裏面的屬性用的是@dynamic

@property有兩個對應的詞,一個是@synthesize,一個是@dynamic。若是@synthesize@dynamic都沒寫,那麼默認的就是@syntheszie var = _var;

 

@synthesize的語義是若是你沒有手動實現setter方法和getter方法,那麼編譯器會自動爲你加上這兩個方法。

@dynamic告訴編譯器,屬性的settergetter方法由用戶本身實現,不自動生成。(固然對於readonly的屬性只需提供getter便可)。假如一個屬性被聲明爲@dynamic var,而後你沒有提供@setter方法和@getter方法,編譯的時候沒問題,可是當程序運行到instance.var =someVar,因爲缺setter方法會致使程序崩潰;或者當運行到 someVar = var時,因爲缺getter方法一樣會致使崩潰。編譯時沒問題,運行時才執行相應的方法,這就是所謂的動態綁定。

而後會再appdelegate裏自動生成如下代碼:

 

#pragma mark - Core Data stack

 

@synthesize managedObjectContext = _managedObjectContext;

@synthesize managedObjectModel = _managedObjectModel;

@synthesize persistentStoreCoordinator = _persistentStoreCoordinator;

 

//存儲在沙盒裏的具體位置

- (NSURL *)applicationDocumentsDirectory {

// The directory the application uses to store the Core Data store file. This code uses a directory named eims.CoreDatatest in the application's documents directory.

return [[[NSFileManager defaultManager] URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask] lastObject];

}

 

//託管對象

- (NSManagedObjectModel *)managedObjectModel {

// The managed object model for the application. It is a fatal error for the application not to be able to find and load its model.

if (_managedObjectModel != nil) {

return _managedObjectModel;

}

NSURL *modelURL = [[NSBundle mainBundle] URLForResource:@CoreDatatest withExtension:@momd];

_managedObjectModel = [[NSManagedObjectModel alloc] initWithContentsOfURL:modelURL];

return _managedObjectModel;

}

//持久化存儲協調器

- (NSPersistentStoreCoordinator *)persistentStoreCoordinator {

// The persistent store coordinator for the application. This implementation creates and return a coordinator, having added the store for the application to it.

if (_persistentStoreCoordinator != nil) {

return _persistentStoreCoordinator;

}

 

// Create the coordinator and store

 

_persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:[self managedObjectModel]];

NSURL *storeURL = [[self applicationDocumentsDirectory] URLByAppendingPathComponent:@CoreDatatest.sqlite];

NSError *error = nil;

NSString *failureReason = @There was an error creating or loading the application's saved data.;

if (![_persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeURL options:nil error:&error]) {

// Report any error we got.

NSMutableDictionary *dict = [NSMutableDictionary dictionary];

dict[NSLocalizedDescriptionKey] = @Failed to initialize the application's saved data;

dict[NSLocalizedFailureReasonErrorKey] = failureReason;

dict[NSUnderlyingErrorKey] = error;

error = [NSError errorWithDomain:@YOUR_ERROR_DOMAIN code:9999 userInfo:dict];

// Replace this with code to handle the error appropriately.

// abort() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development.

NSLog(@Unresolved error %@, %@, error, [error userInfo]);

abort();

}

return _persistentStoreCoordinator;

}

 

//託管上下文

- (NSManagedObjectContext *)managedObjectContext {

// Returns the managed object context for the application (which is already bound to the persistent store coordinator for the application.)

if (_managedObjectContext != nil) {

return _managedObjectContext;

}

NSPersistentStoreCoordinator *coordinator = [self persistentStoreCoordinator];

if (!coordinator) {

return nil;

}

_managedObjectContext = [[NSManagedObjectContext alloc] init];

[_managedObjectContext setPersistentStoreCoordinator:coordinator];

return _managedObjectContext;

}

 

#pragma mark - Core Data Saving support

 

- (void)saveContext {

NSManagedObjectContext *managedObjectContext = self.managedObjectContext;

if (managedObjectContext != nil) {

NSError *error = nil;

if ([managedObjectContext hasChanges] && ![managedObjectContext save:&error]) {

// Replace this implementation with code to handle the error appropriately.

// abort() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development.

NSLog(@Unresolved error %@, %@, error, [error userInfo]);

abort();

}

}

}

這些代碼知道具體做用就好,若是想本身手動創建起來coredata文件,也能夠本身手動寫

下面就是在viewcontroller的具體操做,

先引入appdelegate和User,Department的頭文件

在viewcontroller裏添加

@property (strong, nonatomic)AppDelegate *myAppDelegate;屬性

而後,

具體操做,

添加:

 

User*user = (User*)[NSEntityDescription insertNewObjectForEntityForName:@User inManagedObjectContext:self.myAppDelegate.managedObjectContext];

[user setName:_nametextfield.text];

[user setAge:[NSNumber numberWithInteger:[_agetextfield.text integerValue]]];

[user setSex:_sextextfield.text];

NSError*error;

BOOL isSaveSuccess = [myAppDelegate.managedObjectContext save:&error];//保存(容易忘)

if (!isSaveSuccess) {

NSLog(@Error:%@,error);

_attentiontextview.text = [NSString stringWithFormat:@Error:%@,error];

}else{

NSLog(@Save Successful!);

_attentiontextview.text = @Save Successful!;

}

查詢:

 

//數據請求(請求):命令集

NSFetchRequest*request = [[NSFetchRequest alloc]init];

//NSEntityDescription(實體描述):表

NSEntityDescription*user = [NSEntityDescription entityForName:@Department inManagedObjectContext:myAppDelegate.managedObjectContext];

[request setEntity:user];

NSError*error;

NSArray*mutablefetchResult = [myAppDelegate.managedObjectContext

executeFetchRequest:request error:&error];

if (mutablefetchResult == nil) {

NSLog(@Error: %@,mutablefetchResult);

}

NSLog(@the count of entry:%lu,[mutablefetchResult count]);

NSString*str = @;

 

for (Department*user in mutablefetchResult) {

// NSLog(@name:%@------age:%@-------sex:%@,user.name,user.age,user.sex);

// str = [str stringByAppendingFormat:@name:%@------age:%@-------sex:%@ ---depart:%@ ,user.name,user.age,user.sex,user.userrelationship.departmentname];

str = [str stringByAppendingFormat:@name:%@------ ,user.departmentname];

}

NSLog(@str:%@,str);

更新:

 

//NSFetchRequest 數據請求(請求):命令集

NSFetchRequest*request = [[NSFetchRequest alloc]init];

//NSEntityDescription(實體描述):表

NSEntityDescription*user = [NSEntityDescription entityForName:@User inManagedObjectContext:myAppDelegate.managedObjectContext];

[request setEntity:user];

//設置查詢條件 NSPredicate (謂詞):查詢語句

NSPredicate*predicate = [NSPredicate predicateWithFormat:@name == %@,@lisi];

[request setPredicate:predicate];

NSError*error;

NSArray * mutablFetchResult = [myAppDelegate.managedObjectContext executeFetchRequest:request error:&error];

if (mutablFetchResult == nil) {

NSLog(@Error:%@,error);

_attentiontextview.text = [NSString stringWithFormat:@Error:%@,error];

}

NSLog(@the count of entry:%lu,[mutablFetchResult count]);

for (User*user in mutablFetchResult) {

[user setAge:[NSNumber numberWithInteger:999]];

}

//判斷是否修改爲功

BOOL isSaveSuccess = [myAppDelegate.managedObjectContext save:&error];//保存(容易忘)

if (!isSaveSuccess) {

NSLog(@Error:%@,error);

_attentiontextview.text = [NSString stringWithFormat:@Error:%@,error];

}else{

NSLog(@update Successful!);

_attentiontextview.text = @update Successful!;

}

刪除:

 

//數據請求(命令集)

NSFetchRequest*request = [[NSFetchRequest alloc]init];

//實體描述(表)

NSEntityDescription*user = [NSEntityDescription entityForName:@Department inManagedObjectContext:myAppDelegate.managedObjectContext];

[request setEntity:user];

//設置查詢條件

NSPredicate* predicate = [NSPredicate predicateWithFormat:@departmentname == %@,@公共事業部];

[request setPredicate:predicate];

NSError*error;

NSArray*mutableFetchResult = [myAppDelegate.managedObjectContext executeFetchRequest:request error:&error];

if (mutableFetchResult == nil) {

NSLog(@Error:%@,error);

_attentiontextview.text = [NSString stringWithFormat:@Error:%@,error];

}

NSLog(@mutableFetchResult %lu,[mutableFetchResult count]);

for (User*user in mutableFetchResult) {

[myAppDelegate.managedObjectContext deleteObject:user];

}

//判斷是否刪除成功

BOOL isDeleteSuccess = [myAppDelegate.managedObjectContext save:&error];//保存(容易忘)

if (!isDeleteSuccess) {

NSLog(@Error:%@,error);

_attentiontextview.text = [NSString stringWithFormat:@Error:%@,error];

}else{

NSLog(@delete Successful!);

_attentiontextview.text = @delete Successful!;

}

 

 

coredata並不是嚴格的說是對sqlite數據庫的一個封裝,也能夠用其餘的數據庫,並不必定要使用sqlite3,固然了coredata的好處仍是很是多的,高效,簡介,能節省至少50%的代碼量,條目清新

 

ViewController.m

 

#import "ViewController.h"

#import <CoreData/CoreData.h>

#import "Person.h"

@interface ViewController ()

 

@property(nonatomic,retain) NSManagedObjectContext *context;

@end

 

@implementation ViewController

 

#pragma mark -生命週期方法

- (void)viewDidLoad

{

    [super viewDidLoad];

    [self LoadData];

    

    //[self UdataData];

   // [self addData];

//[self deleteData];

  //  [self searchdata];

    //面向對象操做

    [self addPerson];

    [self searchPerson];

    // Do any additional setup after loading the view, typically from a nib.

}

 

- (void)didReceiveMemoryWarning

{

    [super didReceiveMemoryWarning];

    // Dispose of any resources that can be recreated.

}

 

-(void)viewDidUnload{

    [super viewDidUnload];

    self.context=nil;

}

- (void)dealloc

{

    [_context release];

    [super dealloc];

}

 

#pragma mark-加載數據方式

 

-(void)LoadData{

    //Nil表是從主bundles中加對應的模型實體

    NSManagedObjectModel *model=[NSManagedObjectModel mergedModelFromBundles:nil];

    for (NSEntityDescription *desc in model.entities) {

        NSLog(@"%@",desc.name);

    }

    //經過模型 和數據庫持久化

    NSPersistentStoreCoordinator *storeCoordinator=[[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:model];

    //持久化到coredata中

    NSString *document= [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject];

    document=[document stringByAppendingPathComponent:@"coredata.db"];

    NSURL *url=[NSURL fileURLWithPath:document];

    NSError *error=nil;

    [storeCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:url options:nil error:&error];

    if(error){

        NSLog(@"打開數據庫失敗");

        return;

    }

    

    self.context=[[[NSManagedObjectContext alloc] init] autorelease];

    self.context.persistentStoreCoordinator=storeCoordinator;

    

}

 

-(void)addData{

 

    //把實體對象和實體上下文相關聯

    for (int i=0; i<10; i++) {

        

    

    NSManagedObject *obj=[NSEntityDescription insertNewObjectForEntityForName:@"Person" inManagedObjectContext:self.context];

        NSString *name=[NSString stringWithFormat:@"gcb%i",i];

        int age=i;

    [obj setValue: name forKey:@"name"];

    [obj setValue:@(age) forKey:@"age"];

    

    //保存上下文中相關聯的對象便可

    }

        [self.context save:nil];

    

}

 

-(void)searchdata{

    NSFetchRequest *fetch=[NSFetchRequest fetchRequestWithEntityName:@"Person"];

    

    //排序

    NSSortDescriptor *sort=[NSSortDescriptor sortDescriptorWithKey:@"age" ascending:NO];

    fetch.sortDescriptors=@[sort];

    //加入查詢條件 age>20

//    fetch.predicate=[NSPredicate predicateWithFormat:@"age>%i",20];

    //加入like *c1"

    //fetch.predicate=[NSPredicate predicateWithFormat:@"name like %@",@"*cb1*"];

    NSArray *arr=[self.context executeFetchRequest:fetch error:nil];

    for (NSManagedObject *mode in arr) {

        NSString *name=[mode valueForKey:@"name"];

        int age =[[mode valueForKey:@"age"] intValue];

        NSLog(@"%zi--%@",age,name);

    }

}

//先查詢出要修改的數據

-(void)UdataData{

 //要操做那一張表

    NSFetchRequest *Fetch=[NSFetchRequest fetchRequestWithEntityName:@"Person"];

    //先建立排序描述,在排序

    NSSortDescriptor *sort=[NSSortDescriptor sortDescriptorWithKey:@"age" ascending:NO];

    Fetch.sortDescriptors=@[sort];

  //加入查詢條件

    Fetch.predicate=[NSPredicate predicateWithFormat:@"age>%i",5];

    //把條件加入到上下文進行操做,獲得查詢集合

    NSArray * arr=[self.context executeFetchRequest:Fetch error:nil];

    for (NSManagedObject *obj in arr) {

    //更改實體的數據

        [obj setValue:@(50) forKey:@"age"];

    }

    //同步更數據庫相關聯的數據

    [self.context save:nil];

}

 

//刪除數據, 從數據庫中取出來的對象,叫作NSManaedObject對象

-(void)deleteData{

    //要找出上下文中操做的一張表

    NSFetchRequest *FectchRequest=[NSFetchRequest fetchRequestWithEntityName:@"Person"];

    FectchRequest.predicate=[NSPredicate predicateWithFormat:@"age<%i",50];

    NSArray *arr=[self.context executeFetchRequest:FectchRequest error:nil];

    for (NSManagedObject *obj in arr) {

        [self.context deleteObject:obj];

    }

    //同步數據庫

    [self.context save:nil];

}

 

#pragma mark-面向對象開發

-(void)addPerson{

    //把要插入的實體和當前上下文相關聯

    Person *ps=[NSEntityDescription insertNewObjectForEntityForName:@"Person" inManagedObjectContext:self.context];

    ps.name=@"mj__itcast";

    ps.age=@28;

    //同步數據和上下文相關聯的

    [self.context save:nil];

}

-(void)searchPerson{

    NSFetchRequest *FetchRequest=[NSFetchRequest fetchRequestWithEntityName:@"Person"];

    NSArray *arr=[self.context executeFetchRequest:FetchRequest error:nil];

    for (Person *ps in arr) {

        NSLog(@"name=%@,age=%@",ps.name,ps.age);

    }

}

@end

 

 

多線程是什麼 

多線程是個複雜的概念,按字面意思是同步完成多項任務,提升了資源的使用效率,從硬件、操做系統、應用軟件不一樣的角度去看,多線程被賦予不一樣的內涵,對於硬件,如今市面上多數的CPU都是多核的,多核的CPU運算多線程更爲出色;從操做系統角度,是多任務,如今用的主流操做系統都是多任務的,能夠一邊聽歌、一邊寫博客;對於應用來講,多線程可讓應用有更快的迴應,能夠在網絡下載時,同時響應用戶的觸摸操做。在iOS應用中,對多線程最初的理解,就是併發,它的含義是原來先作燒水,再摘菜,再炒菜的工做,會變成燒水的同時去摘菜,最後去炒菜。

 

2 iOS 中的多線程

 

iOS中的多線程,是Cocoa框架下的多線程,經過Cocoa的封裝,可讓咱們更爲方便的使用線程,作過C++的同窗可能會對線程有更多的理解,好比線程的創立,信號量、共享變量有認識,Cocoa框架下會方便不少,它對線程作了封裝,有些封裝,可讓咱們建立的對象,自己便擁有線程,也就是線程的對象化抽象,從而減小咱們的工程,提供程序的健壯性。

 

GCD是(Grand Central Dispatch)的縮寫 ,從系統級別提供的一個易用地多線程類庫,具備運行時的特色,能充分利用多核心硬件。GCDAPI接口爲C語言的函數,函數參數中多數有Block關於Block的使用參看這裏,爲咱們提供強大的接口對於GCD的使用參見本文

 

 

NSOperationQueue

NSOperation是一個抽象類,它封裝了線程的細節實現,咱們能夠經過子類化該對象,加上NSQueue來同面向對象的思惟,管理多線程程序。具體可參看這裏:一個基於NSOperation的多線程網絡訪問的項目。

   

NSThread

NSThread是一個控制線程執行的對象,它不如NSOperation抽象,經過它咱們能夠方便的獲得一個線程,並控制它。但NSThread的線程之間的併發控制,是須要咱們本身來控制的,能夠經過NSCondition實現。

參看  

iOS多線程編程之NSThread的使用

 

其餘多線程

Cocoa的框架下,通知、Timer和異步函數等都有使用多線程,(待補充).

 

3 iOS多線程常見面試題

在項目何時選擇使用GCD,何時選擇NSOperation

項目中使用NSOperation的優勢是NSOperation是對線程的高度抽象,在項目中使用它,會使項目的程序結構更好,子類化NSOperation的設計思路,是具備面向對象的優勢(複用、封裝),使得實現是多線程支持,而接口簡單,建議在複雜項目中使用。

項目中使用GCD的優勢是GCD自己很是簡單、易用,對於不復雜的多線程操做,會節省代碼量,而Block參數的使用,會是代碼更爲易讀,建議在簡單項目中使用。

 

使用GCD處理多線程,在多核心CPU下,會提升執行效率,下面是一段在項目中使用的GCD代碼。

 

[cpp] view plaincopyprint?

  1. - (void)gcdDownload  
  2. {  
  3. static dispatch_once_t once;  
  4. static dispatch_queue_t queue;  
  5. //create download queue  
  6. dispatch_once(&once, ^{  
  7. queue =dispatch_queue_create("com.xxx.download.background",DISPATCH_QUEUE_CONCURRENT);  
  8. });  
  9. //__block type  
  10. __block BOOL downloadFlag = NO;  
  11. dispatch_async(queue, ^{  
  12. //        downloadFlag = [Download sendRequest:request];  
  13. NSLog(@"長時間任務,如網絡下載");  
  14. });  
  15. dispatch_barrier_async(queue,^{  
  16. if (downloadFlag) {  
  17. NSLog(@"下載成功完成");  
  18. }  
  19. dispatch_async(dispatch_get_main_queue(), ^{  
  20. NSLog(@"執行完下載,回掉回主線程,例如刷新UI");  
  21. });  
  22. });  
  23. }  


能夠向queue裏放多個併發block

 

Grand Central Dispatch (GCD) 是 Apple 開發的一個多核編程的解決方法。該方法在 Mac OS X 10.6 雪豹中首次推出,並隨後被引入到了 iOS4.0 中。GCD 是一個替代諸如 NSThread, NSOperationQueue, NSInvocationOperation 等技術的很高效和強大的技術。

GCD 和 block 的配合使用,能夠方便地進行多線程編程。

應用舉例

讓咱們來看一個編程場景。咱們要在 iPhone 上作一個下載網頁的功能,該功能很是簡單,就是在 iPhone 上放置一個按鈕,點擊該按鈕時,顯示一個轉動的圓圈,表示正在進行下載,下載完成以後,將內容加載到界面上的一個文本控件中。

不用 GCD 前

雖然功能簡單,可是咱們必須把下載過程放到後臺線程中,不然會阻塞 UI 線程顯示。因此,若是不用 GCD, 咱們須要寫以下 3 個方法:

  • someClick 方法是點擊按鈕後的代碼,能夠看到咱們用 NSInvocationOperation 建了一個後臺線程,而且放到 NSOperationQueue 中。後臺線程執行 download 方法。
  • download 方法處理下載網頁的邏輯。下載完成後用 performSelectorOnMainThread 執行 download_completed 方法。
  • download_completed 進行 clear up 的工做,並把下載的內容顯示到文本控件中。

這 3 個方法的代碼以下。能夠看到,雖然 開始下載 –> 下載中 –> 下載完成 這 3 個步驟是整個功能的三步。可是它們卻被切分紅了 3 塊。他們之間由於是 3 個方法,因此還須要傳遞數據參數。若是是複雜的應用,數據參數極可能就不象本例子中的 NSString 那麼簡單了,另外,下載可能放到 Model 的類中來作,而界面的控制放到 View Controller 層來作,這使得原本就分開的代碼變得更加散落。代碼的可讀性大大下降。

使用 GCD 後

若是使用 GCD,以上 3 個方法均可以放到一塊兒,以下所示:

 

// 原代碼塊一

self.indicator.hidden = NO;

[self.indicator startAnimating];

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{

    // 原代碼塊二

    NSURL * url = [NSURL URLWithString:@"http://www.youdao.com"];

    NSError * error;

    NSString * data = [NSString stringWithContentsOfURL:url encoding:NSUTF8StringEncoding error:&error];

    if (data != nil) {

        // 原代碼塊三

        dispatch_async(dispatch_get_main_queue(), ^{

            [self.indicator stopAnimating];

            self.indicator.hidden = YES;

            self.content.text = data;

        });

    } else {

        NSLog(@"error when download:%@", error);

    }

});

首先咱們能夠看到,代碼變短了。由於少了原來 3 個方法的定義,也少了相互之間須要傳遞的變量的封裝。

另外,代碼變清楚了,雖然是異步的代碼,可是它們被 GCD 合理的整合在一塊兒,邏輯很是清晰。若是應用上 MVC 模式,咱們也能夠將 View Controller 層的回調函數用 GCD 的方式傳遞給 Modal 層,這相比之前用 @selector 的方式,代碼的邏輯關係會更加清楚。

block 的定義

block 的定義有點象函數指針,差異是用 ^ 替代了函數指針的 * 號,以下所示:

1

2

3

4

5

6

7

8

9

// 申明變量

 (void) (^loggerBlock)(void);

 // 定義

 

 loggerBlock = ^{

      NSLog(@"Hello world");

 };

 // 調用

 loggerBlock();

可是大多數時候,咱們一般使用內聯的方式來定義 block,即將它的程序塊寫在調用的函數裏面,例如這樣:

1

2

3

 dispatch_async(dispatch_get_global_queue(0, 0), ^{

      // something

 });

從上面你們能夠看出,block 有以下特色:

  1. 程序塊能夠在代碼中之內聯的方式來定義。
  2. 程序塊能夠訪問在建立它的範圍內的可用的變量。

系統提供的 dispatch 方法

爲了方便地使用 GCD,蘋果提供了一些方法方便咱們將 block 放在主線程 或 後臺線程執行,或者延後執行。使用的例子以下:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

 //  後臺執行:

 dispatch_async(dispatch_get_global_queue(0, 0), ^{

      // something

 });

 // 主線程執行:

 dispatch_async(dispatch_get_main_queue(), ^{

      // something

 });

 // 一次性執行:

 static dispatch_once_t onceToken;

 dispatch_once(&onceToken, ^{

     // code to be executed once

 });

 // 延遲 2 秒執行:

 double delayInSeconds = 2.0;

 dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, delayInSeconds * NSEC_PER_SEC);

 dispatch_after(popTime, dispatch_get_main_queue(), ^(void){

     // code to be executed on the main queue after delay

 });

dispatch_queue_t 也能夠本身定義,如要要自定義 queue,能夠用 dispatch_queue_create 方法,示例以下:

1

2

3

4

5

dispatch_queue_t urls_queue = dispatch_queue_create("blog.devtang.com", NULL);

dispatch_async(urls_queue, ^{

     // your code

});

dispatch_release(urls_queue);

另外,GCD 還有一些高級用法,例如讓後臺 2 個線程並行執行,而後等 2 個線程都結束後,再彙總執行結果。這個能夠用 dispatch_group, dispatch_group_async 和 dispatch_group_notify 來實現,示例以下:

1

2

3

4

5

6

7

8

9

10

 dispatch_group_t group = dispatch_group_create();

 dispatch_group_async(group, dispatch_get_global_queue(0,0), ^{

      // 並行執行的線程一

 });

 dispatch_group_async(group, dispatch_get_global_queue(0,0), ^{

      // 並行執行的線程二

 });

 dispatch_group_notify(group, dispatch_get_global_queue(0,0), ^{

      // 彙總結果

 });

修改 block 以外的變量

默認狀況下,在程序塊中訪問的外部變量是複製過去的,即寫操做不對原變量生效。可是你能夠加上 __block 來讓其寫操做生效,示例代碼以下:

1

2

3

4

5

6

 __block int a = 0;

 void  (^foo)(void) = ^{

      a = 1;

 }

 foo();

 // 這裏,a 的值被修改成 1

後臺運行

使用 block 的另外一個用處是可讓程序在後臺較長久的運行。在之前,當 app 被按 home 鍵退出後,app 僅有最多 5 秒鐘的時候作一些保存或清理資源的工做。可是應用能夠調用 UIApplication 的beginBackgroundTaskWithExpirationHandler方法,讓 app 最多有 10 分鐘的時間在後臺長久運行。這個時間能夠用來作清理本地緩存,發送統計數據等工做。

讓程序在後臺長久運行的示例代碼以下:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

// AppDelegate.h 文件

@property (assign, nonatomic) UIBackgroundTaskIdentifier backgroundUpdateTask;

 

// AppDelegate.m 文件

- (void)applicationDidEnterBackground:(UIApplication *)application

{

    [self beingBackgroundUpdateTask];

    // 在這裏加上你須要長久運行的代碼

    [self endBackgroundUpdateTask];

}

 

- (void)beingBackgroundUpdateTask

{

    self.backgroundUpdateTask = [[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:^{

        [self endBackgroundUpdateTask];

    }];

}

 

- (void)endBackgroundUpdateTask

{

    [[UIApplication sharedApplication] endBackgroundTask: self.backgroundUpdateTask];

    self.backgroundUpdateTask = UIBackgroundTaskInvalid;

}

總結

整體來講,GCD 可以極大地方便開發者進行多線程編程。你們應該儘可能使用 GCD 來處理後臺線程和 UI 線程的交互。

 

1.1 iOS有三種多線程編程的技術,分別是:

1.NSThread 

2Cocoa NSOperation iOS多線程編程之NSOperationNSOperationQueue的使用

3GCD  全稱:Grand Central Dispatch iOS多線程編程之Grand Central Dispatch(GCD)介紹和使用

這三種編程方式從上到下,抽象度層次是從低到高的,抽象度越高的使用越簡單,也是Apple最推薦使用的。

這篇咱們主要介紹和使用NSThread,後面會繼續2的講解和使用。

1.2 三種方式的有缺點介紹:

NSThread:

優勢:NSThread 比其餘兩個輕量級

缺點:須要本身管理線程的生命週期,線程同步。線程同步對數據的加鎖會有必定的系統開銷

NSThread實現的技術有下面三種:

通常使用cocoa thread 技術。

 

Cocoa operation 

優勢:不須要關心線程管理,數據同步的事情,能夠把精力放在本身須要執行的操做上。

Cocoa operation 相關的類是 NSOperation NSOperationQueueNSOperation是個抽象類,使用它必須用它的子類,能夠實現它或者使用它定義好的兩個子類:NSInvocationOperation 和 NSBlockOperation。建立NSOperation子類的對象,把對象添加到NSOperationQueue隊列裏執行。

GCD

Grand Central Dispatch (GCD)Apple開發的一個多核編程的解決方法。在iOS4.0開始以後才能使用。GCD是一個替代諸如NSThread, NSOperationQueue, NSInvocationOperation等技術的很高效和強大的技術。如今的iOS系統都升級到6了,因此不用擔憂該技術不能使用。

 

介紹完這三種多線程編程方式,咱們這篇先介紹NSThread的使用。

2NSThread的使用

2.1 NSThread 有兩種直接建立方式:

- (id)initWithTarget:(id)target selector:(SEL)selector object:(id)argument

+ (void)detachNewThreadSelector:(SEL)aSelector toTarget:(id)aTarget withObject:(id)anArgument

第一個是實例方法,第二個是類方法

[cpp] view plaincopy

  1. 1[NSThread detachNewThreadSelector:@selector(doSomething:) toTarget:self withObject:nil];  
  2. 2NSThread* myThread = [[NSThread alloc] initWithTarget:self  
  3. selector:@selector(doSomething:)  
  4. object:nil];  
  5. [myThread start];  

2.2參數的意義:

selector :線程執行的方法,這個selector只能有一個參數,並且不能有返回值。

target  selector消息發送的對象

argument:傳輸給target的惟一參數,也能夠是nil

第一種方式會直接建立線程而且開始運行線程,第二種方式是先建立線程對象,而後再運行線程操做,在運行線程操做前能夠設置線程的優先級等線程信息

2.3 PS:不顯式建立線程的方法:

NSObject的類方法  performSelectorInBackground:withObject: 建立一個線程:
[Obj performSelectorInBackground:@selector(doSomething) withObject:nil];

2.4 下載圖片的例子:

2.4.1  新建singeView app

新建項目,並在xib文件上放置一個imageView控件。按住control鍵拖到viewControll

er.h文件中建立imageView IBOutlet 

ViewController.m中實現:

[cpp] view plaincopy

  1. //  
  2. //  ViewController.m  
  3. //  NSThreadDemo  
  4. //  
  5. //  Created by rongfzh on 12-9-23.  
  6. //  Copyright (c) 2012 rongfzh. All rights reserved.  
  7. //  
  8. #import "ViewController.h"  
  9. #define kURL @"http://avatar.csdn.net/2/C/D/1_totogo2010.jpg"  
  10. @interface ViewController ()  
  11. @end  
  12. @implementation ViewController  
  13. -(void)downloadImage:(NSString *) url{  
  14. NSData *data = [[NSData alloc] initWithContentsOfURL:[NSURL URLWithString:url]];  
  15. UIImage *image = [[UIImage alloc]initWithData:data];  
  16. if(image == nil){  
  17. }else{  
  18. [self performSelectorOnMainThread:@selector(updateUI:) withObject:image waitUntilDone:YES];  
  19. }  
  20. }  
  21. -(void)updateUI:(UIImage*) image{  
  22. self.imageView.image = image;  
  23. }  
  24. - (void)viewDidLoad  
  25. {  
  26. [super viewDidLoad];  
  27. //    [NSThread detachNewThreadSelector:@selector(downloadImage:) toTarget:self withObject:kURL];  
  28. NSThread *thread = [[NSThread alloc]initWithTarget:self selector:@selector(downloadImage:) object:kURL];  
  29. [thread start];  
  30. }  
  31. - (void)didReceiveMemoryWarning  
  32. {  
  33. [super didReceiveMemoryWarning];  
  34. // Dispose of any resources that can be recreated.  
  35. }  
  36. @end  

2.4.2線程間通信

線程下載完圖片後怎麼通知主線程更新界面呢?

[self performSelectorOnMainThread:@selector(updateUI:) withObject:image waitUntilDone:YES];

performSelectorOnMainThreadNSObject的方法,除了能夠更新主線程的數據外,還能夠更新其餘線程的好比:

用:performSelector:onThread:withObject:waitUntilDone: 

運行下載圖片:

 

圖片下載下來了。

2.3 線程同步

咱們演示一個經典的賣票的例子來說NSThread的線程同步:

.h

[cpp] view plaincopy

  1. #import <UIKit/UIKit.h>  
  2. @class ViewController;  
  3. @interface AppDelegate : UIResponder <UIApplicationDelegate>  
  4. {  
  5. int tickets;  
  6. int count;  
  7. NSThread* ticketsThreadone;  
  8. NSThread* ticketsThreadtwo;  
  9. NSCondition* ticketsCondition;  
  10. NSLock *theLock;  
  11. }  
  12. @property (strong, nonatomic) UIWindow *window;  
  13. @property (strong, nonatomic) ViewController *viewController;  
  14. @end  

[cpp] view plaincopy

  1. - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions  
  2. {  
  3. tickets = 100;  
  4. count = 0;  
  5. theLock = [[NSLock alloc] init];  
  6. // 鎖對象  
  7. ticketsCondition = [[NSCondition alloc] init];  
  8. ticketsThreadone = [[NSThread alloc] initWithTarget:self selector:@selector(run) object:nil];  
  9. [ticketsThreadone setName:@"Thread-1"];  
  10. [ticketsThreadone start];  
  11. ticketsThreadtwo = [[NSThread alloc] initWithTarget:self selector:@selector(run) object:nil];  
  12. [ticketsThreadtwo setName:@"Thread-2"];  
  13. [ticketsThreadtwo start];  
  14. self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];  
  15. // Override point for customization after application launch.  
  16. self.viewController = [[ViewController alloc] initWithNibName:@"ViewController" bundle:nil];  
  17. self.window.rootViewController = self.viewController;  
  18. [self.window makeKeyAndVisible];  
  19. return YES;  
  20. }  
  21. - (void)run{  
  22. while (TRUE) {  
  23. // 上鎖  
  24. //        [ticketsCondition lock];  
  25. [theLock lock];  
  26. if(tickets >= 0){  
  27. [NSThread sleepForTimeInterval:0.09];  
  28. count = 100 - tickets;  
  29. NSLog(@"當前票數是:%d,售出:%d,線程名:%@",tickets,count,[[NSThread currentThread] name]);  
  30. tickets--;  
  31. }else{  
  32. break;  
  33. }  
  34. [theLock unlock];  
  35. //        [ticketsCondition unlock];  
  36. }  
  37. }  

若是沒有線程同步的lock,賣票數多是-1.加上lock以後線程同步保證了數據的正確性。
上面例子我使用了兩種鎖,一種NSCondition ,一種是:NSLock。 NSCondition我已經註釋了。

線程的順序執行

他們均可以經過

        [ticketsCondition signal]; 發送信號的方式,在一個線程喚醒另一個線程的等待。

好比:

[cpp] view plaincopy

  1. #import "AppDelegate.h"  
  2. #import "ViewController.h"  
  3. @implementation AppDelegate  
  4. - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions  
  5. {  
  6. tickets = 100;  
  7. count = 0;  
  8. theLock = [[NSLock alloc] init];  
  9. // 鎖對象  
  10. ticketsCondition = [[NSCondition alloc] init];  
  11. ticketsThreadone = [[NSThread alloc] initWithTarget:self selector:@selector(run) object:nil];  
  12. [ticketsThreadone setName:@"Thread-1"];  
  13. [ticketsThreadone start];  
  14. ticketsThreadtwo = [[NSThread alloc] initWithTarget:self selector:@selector(run) object:nil];  
  15. [ticketsThreadtwo setName:@"Thread-2"];  
  16. [ticketsThreadtwo start];  
  17. NSThread *ticketsThreadthree = [[NSThread alloc] initWithTarget:self selector:@selector(run3) object:nil];  
  18. [ticketsThreadthree setName:@"Thread-3"];  
  19. [ticketsThreadthree start];      
  20. self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];  
  21. // Override point for customization after application launch.  
  22. self.viewController = [[ViewController alloc] initWithNibName:@"ViewController" bundle:nil];  
  23. self.window.rootViewController = self.viewController;  
  24. [self.window makeKeyAndVisible];  
  25. return YES;  
  26. }  
  27. -(void)run3{  
  28. while (YES) {  
  29. [ticketsCondition lock];  
  30. [NSThread sleepForTimeInterval:3];  
  31. [ticketsCondition signal];  
  32. [ticketsCondition unlock];  
  33. }  
  34. }  
  35. - (void)run{  
  36. while (TRUE) {  
  37. // 上鎖  
  38. [ticketsCondition lock];  
  39. [ticketsCondition wait];  
  40. [theLock lock];  
  41. if(tickets >= 0){  
  42. [NSThread sleepForTimeInterval:0.09];  
  43. count = 100 - tickets;  
  44. NSLog(@"當前票數是:%d,售出:%d,線程名:%@",tickets,count,[[NSThread currentThread] name]);  
  45. tickets--;  
  46. }else{  
  47. break;  
  48. }  
  49. [theLock unlock];  
  50. [ticketsCondition unlock];  
  51. }  
  52. }  

wait是等待,我加了一個 線程去喚醒其餘兩個線程鎖中的wait

其餘同步

咱們能夠使用指令 @synchronized 來簡化 NSLock的使用,這樣咱們就沒必要顯示編寫建立NSLock,加鎖並解鎖相關代碼。
- (void)doSomeThing:(id)anObj
{
    @synchronized(anObj)
    {
        // Everything between the braces is protected by the @synchronized directive.
    }
}
還有其餘的一些鎖對象,好比:循環鎖NSRecursiveLock,條件鎖NSConditionLock,分佈式鎖NSDistributedLock等等

 

什麼是block

對於閉包(block),有不少定義,其中閉包就是可以讀取其它函數內部變量的函數,這個定義即接近本質又較好理解。對於剛接觸Block的同窗,會以爲有些繞,由於咱們習慣寫這樣的程序main(){ funA();} funA(){funB();} funB(){.....}; 就是函數main調用函數A,函數A調用函數B... 函數們依次順序執行,但現實中不全是這樣的,例如項目經理M,手下有3個程序員ABC,當他給程序員A安排實現功能F1時,他並不等着A完成以後,再去安排B去實現F2,而是安排給A功能F1B功能F2C功能F3,而後可能去寫技術文檔,而當A遇到問題時,他會來找項目經理M,當B作完時,會通知M,這就是一個異步執行的例子。在這種情形下,Block即可大顯身手,由於在項目經理M,給A安排工做時,同時會告訴A若果遇到困難,如何能找到他報告問題(例如打他手機號),這就是項目經理MA的一個回調接口,要回掉的操做,好比接到電話,百度查詢後,返回網頁內容給A,這就是一個Block,在M交待工做時,已經定義好,而且取得了F1的任務號(局部變量),倒是在當A遇到問題時,才調用執行,跨函數在項目經理M查詢百度,得到結果後回調該block

 

2 block 實現原理

Objective-C是對C語言的擴展,block的實現是基於指針和函數指針。

從計算語言的發展,最先的goto,高級語言的指針,到面嚮對象語言的block,從機器的思惟,一步步接近人的思惟,以方便開發人員更爲高效、直接的描述出現實的邏輯(需求)。

下面是兩篇很好的介紹block實現的博文

iOSblock實現的探究

Objective-C Block的實現

 

 

3 block的使用

使用實例

cocoaTouch框架下動畫效果的Block的調用

 

使用typed聲明block

typedef void(^didFinishBlock) (NSObject *ob);

這就聲明瞭一個didFinishBlock類型的block

而後即可用

@property (nonatomic,copy) didFinishBlock  finishBlock;

聲明一個block對象,注意對象屬性設置爲copy,接到block 參數時,便會自動複製一份。

 

__block是一種特殊類型,

使用該關鍵字聲明的局部變量,能夠被block所改變,而且其在原函數中的值會被改變。

 

 

常見系列面試題

面試時,面試官會先問一些,是否瞭解block,是否使用過block,這些問題至關於開場白,每每是下面一系列問題的開始,因此必定要如實根據本身的狀況回答。

使用block和使用delegate完成委託模式有什麼優勢?

首先要了解什麼是委託模式,委託模式在iOS中大量應用,其在設計模式中是適配器模式中的對象適配器,Objective-C中使用id類型指向一切對象,使委託模式更爲簡潔。瞭解委託模式的細節:

 iOS設計模式----委託模式 

使用block實現委託模式,其優勢是回調的block代碼塊定義在委託對象函數內部,使代碼更爲緊湊;

適配對象再也不須要實現具體某個protocol,代碼更爲簡潔。

 

 

多線程與block

GCDBlock

使用 dispatch_async 系列方法,能夠以指定的方式執行block

GCD編程實例

 

dispatch_async的完整定義

   void dispatch_async(

   dispatch_queue_t queue,

   dispatch_block_t block);

功能:在指定的隊列裏提交一個異步執行的block,不阻塞當前線程

 

經過queue來控制block執行的線程。主線程執行前文定義的 finishBlock對象

dispatch_async(dispatch_get_main_queue(),^(void){finishBlock();}); 

 

 

談談對Block 的理解?並寫出一個使用Block執行UIVew動畫?

答案:Block是能夠獲取其餘函數局部變量的匿名函數,其不但方便開發,而且能夠大幅提升應用的執行效率(多核心CPU可直接處理Block指令)

 

[cpp] view plaincopyprint?

  1. [UIView transitionWithView:self.view  
  2. duration:0.2  
  3. options:UIViewAnimationOptionTransitionFlipFromLeft  
  4. animations:^{ [[blueViewController view] removeFromSuperview]; [[self view] insertSubview:yellowViewController.view atIndex:0]; }  
  5. completion:NULL];  

 

寫出上面代碼的Block的定義。

答案:

typedef void(^animations) (void);

typedef void(^completion) (BOOL finished);

 

試着使用+ beginAnimations:context:以及上述Block的定義,寫出一個能夠完成

+ (void)transitionWithView:(UIView *)view duration:(NSTimeInterval)duration options:(UIViewAnimationOptions)options animations:(void (^)(void))animations completion:(void (^)(BOOL finished))completion NS_AVAILABLE_IOS(4_0);操做的函數執行部分

答案:無

網絡部分

作過的項目是否涉及網絡訪問功能,使用什麼對象完成網絡功能?

答案:ASIHTTPRequestNSURLConnection

簡單介紹下NSURLConnection類及+ sendSynchronousRequest:returningResponse:error:– initWithRequest:delegate:兩個方法的區別?

答案:  NSURLConnection主要用於網絡訪問,其中+ sendSynchronousRequest:returningResponse:error:是同步訪問數據,即當前線程會阻塞,並等待request的返回的response,而– initWithRequest:delegate:使用的是異步加載,當其完成網絡訪問後,會經過delegate回到主線程,並其委託的對象。

動畫效果是IOS界面重要的特點之一,其中CAAnimation是全部動畫對象的抽象父類,做爲新人,使用較多的是UIView下的動畫方法(類方法)。使用UIView下的動畫,有下面幾個方法。

方法一:設置beginAnimations

其中memberView爲須要添加的子視圖的視圖,mivc.view爲子視圖,在使用的時候,須要將這兩個地方替換

[cpp] view plaincopyprint?

  1. [UIView beginAnimations:@"view flip" context:nil];  
  2. [UIView setAnimationDuration:1];  
  3. [UIView setAnimationTransition:UIViewAnimationTransitionFlipFromRight forView:memberView cache:YES];  
  4. [memberView addSubview:mivc.view];  
  5. [UIView commitAnimations];  


須要注意的是,必定要使用[UIView commitAnimations];動畫纔會生效

經過[UIView setAnimationDuration:1]; 設置持續時間。

 

IOS4.0後,咱們有了新的方法,+ (void)transitionWithView:(UIView *)view duration:(NSTimeInterval)duration options:(UIViewAnimationOptions)options animations:(void (^)(void))animations completion:(void (^)(BOOL finished))completion,依然是UIView的類方法,但使用到了Block對象,Block對象是一組指令,能夠傳遞(像變量同樣),能夠把它想像成C語言的函數指針。

方法二:

其中在當前視圖下,刪除[blueViewController view],添加[yellowViewController view],在使用時,這兩個地方要替換

[cpp] view plaincopyprint?

  1. [UIView transitionWithView:self.view  
  2. duration:0.2  
  3. options:UIViewAnimationOptionTransitionFlipFromLeft  
  4. animations:^{ [[blueViewController view] removeFromSuperview]; [[self view] insertSubview:yellowViewController.view atIndex:0]; }  
  5. completion:NULL];  

其中animations:後的block爲對特定視圖發生的改變,其不能爲是NULLcompletionblock爲動畫執行完後,須要執行的代碼塊,能夠爲NULL

根據手冊,在整個動畫過程當中,用戶交互對於此視圖是暫時無效的(而IOS5.0前,動畫過程當中,用戶交互對於整個應用是無效的),若是想要用戶能夠和視圖交互,能夠改變 UIViewAnimationOptionAllowUserInteraction 的值。

 

Cocoa Touch框架下使用大量使用委託(delegation),根據蘋果公司的文檔,delegateCocoa Touch框架所採用的委託模式的一種形式。實例代碼下載傳送門

理解委託,所須要的準備

(一)協議

Objective-C的協議,相似於C++的抽象類,JAVA的接口。其具體定義以下

[cpp] view plaincopyprint?

  1. @protocol MyButtonDelegate <NSObject>  
  2. @optional  
  3. - (void) didPressButton;  
  4. @end  

 

@protocol爲協議關鍵字,MyButtonDelegate爲協議名,didPressButton爲協議裏的方法。

(二)id類型

id類型能夠理解爲能夠指向任意對象的指針,

其定義爲:

[cpp] view plaincopyprint?

  1. typedef struct objc_class *Class;  
  2. typedef struct objc_object {  
  3. Class isa;  
  4. } *id;  

 

(三)適配器模式

在設計模式中,並無委託模式。但有適配器模式,適配器模式能夠這樣來理解,假如咱們去了香港,要給我電腦接電源,發現有些插板怎麼也插不上(香港使用的是英式插頭),只能先插個轉換器,在把電腦接到轉換器上。這就是生活中的適配器模式,大多數委託模式,就是實現的對象適配器的功能,

(四)實例

咱們想實現一個本身構建的相似於UIButton功能的組件。首先,從UIView繼承下來Mybutton,這時候遇到一個問題,咱們不知道將來誰會用到Mybutton,但咱們知道每一個用到mybutton的,都須要在這個按鈕被按下時,得到一個消息,來告訴用到mybutton的對象(Adaptee),mybuttton被按下。

這時候咱們的適配的<Target>以下:

[cpp] view plaincopyprint?

  1. @protocol MyButtonDelegate <NSObject>  
  2. @optional  
  3. - (void) didPressButton;  
  4. @end  


個人AdapterMybutton,其經過

[cpp] view plaincopyprint?

  1. @property (nonatomic,assign) id <MyButtonDelegate>delegate;  

 

[cpp] view plaincopyprint?

  1. if (delegate && [delegate respondsToSelector:@selector(didPressButton)]) {  
  2. [delegate performSelector:@selector(didPressButton)];  
  3. }  

 

來實現對Adaptee的調用,其中Adaptee能夠是任意對象,在這個例子中,是RootViewController(實現了<MyButtonDelegate>協議)

(五)委託模式的深刻理解

委託模式的實現,也能夠經過Block來實現,但僅適合一次性回調執行的代碼。

 

1.When to use NSMutableArray and when to use NSArray? 

何時使用NSMutableArray,何時使用NSArray

答案:當數組在程序運行時,須要不斷變化的,使用NSMutableArray,當數組在初始化後,便再也不改變的,使用NSArray。須要指出的是,使用NSArray只代表的是該數組在運行時不發生改變,即不能往NSAarry的數組裏新增和刪除元素,但不代表其數組內的元素的內容不能發生改變。NSArray是線程安全的,NSMutableArray不是線程安全的,多線程使用到NSMutableArray須要注意。

2.Give us example of what are delegate methods and what are data source methods of uitableview.

給出委託方法的實例,而且說出UITableVIewData Source方法

答案:CocoaTouch框架中用到了大量委託,其中UITableViewDelegate就是委託機制的典型應用,是一個典型的使用委託來實現適配器模式,其中UITableViewDelegate協議是目標,tableview是適配器,實現UITableViewDelegate協議,並將自身設置爲talbeviewdelegate的對象,是被適配器,通常狀況下該對象是UITableViewController

UITableVIewData Source方法有- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section;

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath;

 

3.How many autorelease you can create in your application? Is there any limit?

在應用中能夠建立多少autorelease對象,是否有限制?

答案:無

4.If we don’t create any autorelease pool in our application then is there any autorelease pool already provided to us?

若是咱們不建立內存池,是否有內存池提供給咱們?

答案:界面線程維護着本身的內存池,用戶本身建立的數據線程,則須要建立該線程的內存池

5.When you will create an autorelease pool in your application?

何時須要在程序中建立內存池?

答案:用戶本身建立的數據線程,則須要建立該線程的內存池

6.When retain count increase?

何時內存計數會增長?

答案:iOS面試題(一)

7.What are commonly used NSObject class methods?

NSObject的那些方法常常被使用?

答案:NSObjectObjetive-C的基類,其由NSObject類及一系列協議構成。

其中類方法allocclass、 description 對象方法initdealloc– performSelector:withObject:afterDelay:等常常被使用 

8.What is convenience constructor?

什麼是簡便構造方法?

答案:簡便構造方法通常由CocoaTouch框架提供,如NSNumber + numberWithBool:  + numberWithChar:  + numberWithDouble:  + numberWithFloat:  + numberWithInt:

Foundation下大部分類均有簡便構造方法,咱們能夠經過簡便構造方法,得到系統給咱們建立好的對象,而且不須要手動釋放。

9.How to design universal application in Xcode?

如何使用Xcode設計通用應用?

答案:使用MVC模式設計應用,其中Model層完成脫離界面,即在Model層,其是可運行在任何設備上,在controller層,根據iPhoneiPad(獨有UISplitViewController)的不一樣特色選擇不一樣的viewController對象。在View層,可根據現實要求,來設計,其中以xib文件設計時,其設置其爲universal

10.What is keyword atomic in Objective C?

Objetive-C什麼時原子關鍵字

答案:atomicnonatomiciOS面試題(一)

11.What are UIView animations?

UIView的動畫效果有那些?

答案:有不少,如  UIViewAnimationOptionCurveEaseInOut     UIViewAnimationOptionCurveEaseIn     UIViewAnimationOptionCurveEaseOut    UIViewAnimationOptionTransitionFlipFromLeft   UIViewAnimationOptionTransitionFlipFromRight     UIViewAnimationOptionTransitionCurlUpUIViewAnimationOptionTransitionCurlDown 

如何使用可見該博文

12.How can you store data in iPhone applications?

iPhone應用中如何保存數據?

答案:有如下幾種保存機制:

1.經過web服務,保存在服務器上

2.經過NSCoder固化機制,將對象保存在文件中

3.經過SQliteCoreData保存在文件數據庫中

13.What is coredata?

什麼是coredata

答案:coredata框架是apple提供的一套通用自動的解決方案,包括了對象生存週期、對象關係圖、持久化機制。

補充答案:上面是翻譯的,按我我的理解coredata提供一種一機制,讓咱們能夠方便的把內存中對象,及對象間的關係,映射到coredata,而後由它爲咱們持久化數據。相比普通的文件數據庫SQlite,它的功能更強大,不須要咱們先將對象數據formatSQL語句,存入數據庫,再用select語句讀出,而如今是從內存到coredata的數據管理,咱們只需管理coredatamanaged對象。

是蘋果提供一套數據保存

14.What is NSManagedObject model?

什麼是NSManagedObject模型?

答案:NSManagedObjectNSObject的子類 ,也是coredata的重要組成部分,它是一個通用的類,實現了core data 模型層所需的基本功能,用戶可經過子類化NSManagedObject,創建本身的數據模型。

15.What is NSManagedobjectContext?

什麼是NSManagedobjectContext

答案:NSManagedobjectContext對象負責應用和數據庫之間的交互。

16.What is predicate?

什麼是謂詞?

答案:謂詞是經過NSPredicate,是經過給定的邏輯條件做爲約束條件,完成對數據的篩選。

    predicate = [NSPredicate predicateWithFormat:@"customerID == %d",n];

    a = [customers filteredArrayUsingPredicate:predicate];

 

17.What kind of persistence store we can use with coredata?

coredata有哪幾種持久化存儲機制?

答案:coredatat提供如下幾種存儲機制:XMLiOS系統不支持),自動存儲,SQLite,內存存儲。 

補充說明:這個問題問的是,coredate框架的存儲機制,平時使用coredata時,更多關注的是managed的對象,這裏是coerdata框架的存儲實現細節。BTW: 其餘經常使用的持久化存儲方法 :存入到文件、 存入到NSUserDefaults(系統plist文件中)。

 

1.Difference between shallow copy and deep copy?
淺複製和深複製的區別?
答案:淺層複製:只複製指向對象的指針,而不復制引用對象自己。
深層複製:複製引用對象自己。
意思就是說我有個A對象,複製一份後獲得A_copy對象後,對於淺複製來講,AA_copy指向的是同一個內存資源,複製的只不過是是一個指針,對象自己資源
仍是隻有一份,那若是咱們對A_copy執行了修改操做,那麼發現A引用的對象一樣被修改,這其實違背了咱們複製拷貝的一個思想。深複製就好理解了,內存中存在了
兩份獨立對象自己。

2.What is advantage of categories? What is difference between implementing a category and inheritance?
類別的做用?繼承和類別在實現中有何區別?
答案:category 能夠在不獲悉,不改變原來代碼的狀況下往裏面添加新的方法,只能添加,不能刪除修改。
而且若是類別和原來類中的方法產生名稱衝突,則類別將覆蓋原來的方法,由於類別具備更高的優先級。
類別主要有3個做用:
(1)將類的實現分散到多個不一樣文件或多個不一樣框架中。
(2)建立對私有方法的前向引用。
(3)向對象添加非正式協議。
 繼承能夠增長,擴展父類方法,而且能夠增長屬性。

3.Difference between categories and extensions?
類別和類擴展的區別。
 答案:categoryextensions的不一樣在於 後者能夠添加屬性。另外後者添加的方法是必需要實現的。
extensions能夠認爲是一個私有的Category

4.Difference between protocol in objective c and interfaces in java?
oc中的協議和java中的接口概念有何不一樣?
答案:OC中的協議有2層含義,官方定義爲 formalinformal protocol。前者和Java接口同樣。
informal protocol中的方法屬於設計模式考慮範疇,不是必須實現的,可是若是有實現,就會改變類的屬性。
其實關於正式協議,類別和非正式協議我很早前學習的時候大體看過,也寫在了學習教程裏
「非正式協議概念其實就是類別的另外一種表達方式「這裏有一些你可能但願實現的方法,你能夠使用他們更好的完成工做」。
這個意思是,這些是可選的。好比我門要一個更好的方法,咱們就會申明一個這樣的類別去實現。而後你在後期能夠直接使用這些更好的方法。
這麼看,總以爲類別這玩意兒有點像協議的可選協議。"
如今來看,其實protocal已經開始對二者都統一和規範起來操做,由於資料中說「非正式協議使用interface修飾「,
如今咱們看到協議中兩個修飾詞:「必須實現(@requied)」和「可選實現(@optional)」。

OC中的協議(formal protocol)java中的接口概念基本一致,OC中非正式協議(informal protocol)就是類別。在java中若是繼承了接口,但不實現其方法,會獲得一個error(沒法編譯);在OC中的正式協議,若是不實現,會獲得一個warning(可編譯執行),若是想去除waring,還能夠加關鍵字(@optional),讓它可選實現方法。

5.What are KVO and KVC?
答案:kvc:鍵 值編碼是一種間接訪問對象的屬性使用字符串來標識屬性,而不是經過調用存取方法,直接或經過實例變量訪問的機制。
不少狀況下能夠簡化程序代碼。apple文檔其實給了一個很好的例子。
kvo:鍵值觀察機制,他提供了觀察某一屬性變化的方法,極大的簡化了代碼。
具體用看到嗯哼用到過的一個地方是對於按鈕點擊變化狀態的的監控。
好比我自定義的一個button
[cpp] 
[self addObserver:self forKeyPath:@"highlighted" options:0 context:nil]; 
 
 
#pragma mark KVO 
 
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context 

    if ([keyPath isEqualToString:@"highlighted"] ) { 
        [self setNeedsDisplay]; 
    } 

對於系統是根據keypath去取的到相應的值發生改變,理論上來講是和kvc機制的道理是同樣的。
對於kvc機制如何經過key尋找到value
「當經過KVC調用對象時,好比:[self valueForKey:@someKey]時,程序會自動試圖經過幾種不一樣的方式解析這個調用。首先查找對象是否帶有 someKey 這個方法,若是沒找到,會繼續查找對象是否帶有someKey這個實例變量(iVar),若是尚未找到,程序會繼續試圖調用 -(id) valueForUndefinedKey:這個方法。若是這個方法仍是沒有被實現的話,程序會拋出一個NSUndefinedKeyException異常錯誤。
 
(cocoachina.com注:Key-Value Coding查找方法的時候,不只僅會查找someKey這個方法,還會查找getsomeKey這個方法,前面加一個get,或者_someKey以及_getsomeKey這幾種形式。同時,查找實例變量的時候也會不只僅查找someKey這個變量,也會查找_someKey這個變量是否存在。)
 
設計valueForUndefinedKey:方法的主要目的是當你使用-(id)valueForKey方法從對象中請求值時,對象可以在錯誤發生前,有最後的機會響應這個請求。這樣作有不少好處,下面的兩個例子說明了這樣作的好處。「
來至cocoa,這個說法應該挺有道理。
由於咱們知道button倒是存在一個highlighted實例變量.所以爲什麼上面咱們只是add一個相關的keypath就好了,
能夠按照kvc查找的邏輯理解,就說的過去了。

6.What is purpose of delegates?
代理的做用?
答案:代理的目的是改變或傳遞控制鏈。容許一個類在某些特定時刻通知到其餘類,而不須要獲取到那些類的指針。能夠減小框架複雜度。
另一點,代理能夠理解爲java中的回調監聽機制的一種相似。

7.What are mutable and immutable types in Objective C?
oc中可修改和不能夠修改類型。
答案:可修改不可修改的集合類。這個我我的簡單理解就是可動態添加修改和不可動態添加修改同樣。
好比NSArrayNSMutableArray。前者在初始化後的內存控件就是固定不可變的,後者能夠添加等,能夠動態申請新的內存空間。

8.When we call objective c is runtime language what does it mean?
咱們說的oc是動態運行時語言是什麼意思?
答案:多態。 主要是將數據類型的肯定由編譯時,推遲到了運行時。
這個問題其實淺涉及到兩個概念,運行時和多態。
簡單來講,運行時機制使咱們直到運行時纔去決定一個對象的類別,以及調用該類別對象指定方法。
多態:不一樣對象以本身的方式響應相同的消息的能力叫作多態。意思就是假設生物類(life)都用有一個相同的方法-eat;
那人類屬於生物,豬也屬於生物,都繼承了life後,實現各自的eat,可是調用是咱們只需調用各自的eat方法。
也就是不一樣的對象以本身的方式響應了相同的消息(響應了eat這個選擇器)。
所以也能夠說,運行時機制是多態的基礎?~~~

9.what is difference between NSNotification and protocol?
通知和協議的不一樣之處?
答案:協議有控制鏈(has-a)的關係,通知沒有。
首先我一開始也不太明白,什麼叫控制鏈(專業術語了~)。可是簡單分析下通知和代理的行爲模式,咱們大體能夠有本身的理解
簡單來講,通知的話,它能夠一對多,一條消息能夠發送給多個消息接受者。
代理按咱們的理解,到不是直接說不能一對多,好比咱們知道的明星經濟代理人,不少時候一個經濟人負責好幾個明星的事務。
只是對於不一樣明星間,代理的事物對象都是不同的,一一對應,不可能說明天要處理A明星要一個發佈會,代理人發出處理髮佈會的消息後,別稱B
發佈會了。可是通知就不同,他只關心發出通知,而不關心多少接收到感興趣要處理。
所以控制鏈(has-a從英語單詞大體能夠看出,單一擁有和可控制的對應關係。

10.What is push notification?
什麼是推送消息?
答案: 
推送通知更是一種技術。
簡單點就是客戶端獲取資源的一種手段。
普通狀況下,都是客戶端主動的pull
推送則是服務器端主動push 測試push的實現能夠查看該博文。

 

11.Polymorphism
關於多態性
答案:多態,父類指針指向子類對象。
這個題目其實能夠出到一切面向對象語言中,
所以關於多態,繼承和封裝基本最好都有個自我意識的理解,也並不是必定要把書上資料上寫的能背出來。
最重要的是轉化成自我理解。

12.Singleton?
對於單例的理解
答案:1112題目其實出的有點泛泛的感受了,可能說是編程語言須要或是必備的基礎。
基本能用熟悉的語言寫出一個單例,以及能夠運用到的場景或是你編程中碰到過運用的此種模式的框架類等。
進一步點,考慮下如何在多線程訪問單例時的安全性。

13.What is responder chain?
說說響應鏈
答案: 事件響應鏈。包括點擊事件,畫面刷新事件等。在視圖棧內從上至下,或者從下之上傳播。
能夠說點事件的分發,傳遞以及處理。具體能夠去看下touch事件這塊。由於問的太抽象化了
嚴重懷疑題目出到越後面就越籠統。

能夠從責任鏈模式,來說經過事件響應鏈處理,其擁有的擴展性

14.Difference between frame and bounds?
framebounds有什麼不一樣?
答案:frame指的是:該view在父view座標系統中的位置和大小。(參照點是父親的座標系統)
bounds指的是:該view在自己座標系統中 的位置和大小。(參照點是自己座標系統)

15.Difference between method and selector?
方法和選擇器有何不一樣?
答案:selector是一個方法的名字,method是一個組合體,包含了名字和實現.
詳情能夠看apple文檔。

16.Is there any garbage collection mechanism in Objective C.?
OC的垃圾回收機制?
答案: OC2.0Garbage collection,可是iOS平臺不提供。
通常咱們瞭解的objective-c對於內存管理都是手動操做的,可是也有自動釋放池。
可是差了大部分資料,貌似不要和arc機制搞混就行了。
求更多~~

17.NSOperation queue?
答案:存放NSOperation的集合類。
操做和操做隊列,基本能夠當作java中的線程和線程池的概念。用於處理ios多線程開發的問題。
網上部分資料提到一點是,雖然是queue,可是卻並非帶有隊列的概念,放入的操做並不是是按照嚴格的先進現出。
這邊又有個疑點是,對於隊列來講,先進先出的概念是Afunc添加進隊列,Bfunc緊跟着也進入隊列,Afunc先執行這個是必然的,
可是Bfunc是等Afunc徹底操做完之後,B纔開始啓動而且執行,所以隊列的概念理論上有點違背了多線程處理這個概念。
可是轉念一想其實能夠參考銀行的取票和叫號系統。
所以對於AB先排隊取票可是B率先執行完操做,咱們亦然能夠感性認爲這仍是一個隊列。
可是後來看到一票關於這操做隊列話題的文章,其中有一句提到
「由於兩個操做提交的時間間隔很近,線程池中的線程,誰先啓動是不定的。」
瞬間以爲這個queue名字有點忽悠人了,還不如pool~
綜合一點,咱們知道他能夠比較大的用處在於能夠幫助多線程編程就行了。

樓上區分了線程執行時的次序(AfuncBfunc誰先啓動)和線程執行完成(AfuncBfunc誰先執行完)時的次序不一樣,而多線程的重要概念是併發(同時執行多個任務),NSOperationQueue是管理併發線程的對象,能夠在其中放入NSOpertation對象(對象化的線程實體),經過設置maxConcurrentOperationCount的大小,控制併發數目,如樓上所說但願「Afunc添加進隊列,執行完後,Bfunc緊跟進入隊列,繼續執行」,那隻需將maxConcurrentOperationCount設爲1,變會依次執行,這時候實際是在單線程依次執行。因此這裏的NSOperationQueue就是對象化抽象的去管理多線程,這樣的好處,使用者經過繼承NSOperation對象,能夠方便的用對象來管理線程,而再也不用關心線程同步、信號量等細節,更多地關注於業務邏輯

18.What is lazy loading?
答案:懶漢模式,只在用到的時候纔去初始化。
也能夠理解成延時加載。
我以爲最好也最簡單的一個列子就是tableView中圖片的加載顯示了。
一個延時載,避免內存太高,一個異步加載,避免線程堵塞。

19.Can we use two tableview controllers on one viewcontroller?
是否在一個視圖控制器中嵌入兩個tableview控制器?
答案:一個視圖控制只提供了一個View視圖,理論上一個tableViewController也不能放吧,
只能說能夠嵌入一個tableview視圖。固然,題目自己也有歧義,若是不是咱們定性思惟認爲的UIViewController
而是宏觀的表示視圖控制者,那咱們卻是能夠把其當作一個視圖控制者,它能夠控制多個視圖控制器,好比TabbarController
那樣的感受。

20.Can we use one tableview with two different datasources? How you will achieve this?
一個tableView是否能夠關聯兩個不一樣的數據源?你會怎麼處理?
答案:首先咱們從代碼來看,數據源如何關聯上的,實際上是在數據源關聯的代理方法裏實現的。
所以咱們並不關心如何去關聯他,他怎麼關聯上,方法只是讓我返回根據本身的須要去設置如相關的數據源。
所以,我以爲能夠設置多個數據源啊,可是有個問題是,你這是想幹嗎呢?想讓列表如何顯示,不一樣的數據源分區塊顯示?

 

1.   Objectc的類能夠多重繼承麼?能夠實現多個接口麼?Category是什麼?重寫一個類的方式用繼承好仍是分類好?爲何?

Object-c的類不能夠多重繼承;能夠實現多個接口,經過實現多個接口能夠完成C++的多重繼承;Category是類別,通常狀況用分類好,用Category去重寫類的方法,僅對本Category有效,不會影響到其餘類與原有類的關係。

 

2.#import #include 又什麼區別,@classimport<> 跟 #import」"又什麼區別?

#importObjective-C導入頭文件的關鍵字,#includeC/C++導入頭文件的關鍵字,使用#import頭文件會自動只導入一次,不會重複導入,至關於#include#pragma once@class告訴編譯器某個類的聲明,當執行時,纔去查看類的實現文件,能夠解決頭文件的相互包含;#import<>用來包含系統的頭文件,#import」」用來包含用戶頭文件。

 

3. 屬性readwritereadonlyassignretaincopynonatomic 各是什麼做用,在那種狀況下用?

readwrite 是可讀可寫特性;須要生成getter方法和setter方法時

readonly 是隻讀特性  只會生成getter方法 不會生成setter方法 ;不但願屬性在類外改變

assign 是賦值特性,setter方法將傳入參數賦值給實例變量;僅設置變量時;

retain 表示持有特性,setter方法將傳入參數先保留,再賦值,傳入參數的retaincount+1;

copy 表示拷貝特性,setter方法將傳入對象複製一份;須要徹底一份新的變量時。

nonatomic 非原子操做,決定編譯器生成的setter getter是不是原子操做,atomic表示多線程安全,通常使用nonatomic

 

4.寫一個setter方法用於完成@property nonatomic,retainNSString *name,寫一個setter方法用於完成@propertynonatomiccopyNSString *name

[cpp] view plaincopyprint?

  1. - (void)setName:(NSString *) str  
  2. {  
  3. [str retain];  
  4. [name release];  
  5. name = str;  
  6. }  
  7. - (void)setName:(NSString *)str  
  8. {  
  9. id t = [str copy];  
  10. [name release];  
  11. name = t;  
  12. }  

 

5.對於語句NSString*obj = [[NSData alloc] init]; obj在編譯時和運行時分別時什麼類型的對象?

編譯時是NSString的類型;運行時是NSData類型的對象

 

6.常見的object-c的數據類型有那些, 和C的基本數據類型有什麼區別?如:NSIntegerint

object-c的數據類型有NSStringNSNumberNSArrayNSMutableArrayNSData等等,這些都是class,建立後即是對象,而C語言的基本數據類型int,只是必定字節的內存空間,用於存放數值;NSInteger是基本數據類型,並非NSNumber的子類,固然也不是NSObject的子類。NSInteger是基本數據類型Int或者Long的別名(NSInteger的定義typedef long NSInteger),它的區別在於,NSInteger會根據系統是32位仍是64位來決定是自己是int仍是Long 

7.id 聲明的對象有什麼特性?

Id 聲明的對象具備運行時的特性,便可以指向任意類型的objcetive-c的對象;

 

8.Objective-C如何對內存管理的,說說你的見解和解決方法?

Objective-C的內存管理主要有三種方式ARC(自動內存計數)、手動內存計數、內存池。

 

9.內存管理的幾條原則時什麼?按照默認法則.那些關鍵字生成的對象

須要手動釋放?在和property結合的時候怎樣有效的避免內存泄露?

誰申請,誰釋放

遵循Cocoa Touch的使用原則;

內存管理主要要避免過早釋放內存泄漏,對於過早釋放須要注意@property設置特性時,必定要用對特性關鍵字,對於內存泄漏,必定要申請了要負責釋放,要細心。

關鍵字alloc new 生成的對象須要手動釋放;

設置正確的property屬性,對於retain須要在合適的地方釋放,

 

10.如何對iOS設備進行性能測試?

Profile-> Instruments ->Time Profiler

11.看下面的程序,第一個NSLog會輸出什麼?這時strretainCount是多少?第二個和第三個呢? 爲何?

[cpp] view plaincopyprint?

  1. =======================================================  
  2. NSMutableArray* ary = [[NSMutableArray array] retain];  
  3. NSString *str = [NSString stringWithFormat:@"test"];  
  4. [strretain];  
  5. [aryaddObject:str];  
  6. NSLog(@"%@%d",str,[str retainCount]);  
  7. [strretain];  
  8. [strrelease];  
  9. [strrelease];  
  10. NSLog(@"%@%d",str,[str retainCount]);  
  11. [aryremoveAllObjects];  
  12. NSLog(@"%@%d",str,[str retainCount]);  
  13. =======================================================  

strretainCount建立+1retain+1,加入數組自動+1

3

retain+1release-1release-1

2

數組刪除全部對象,全部數組內的對象自動-1

1

12. Object C中建立線程的方法是什麼?若是在主線程中執行代碼,方法是什麼?若是想延時執行代碼、方法又是什麼?

線程建立有三種方法:使用NSThread建立、使用GCDdispatch、使用子類化的NSOperation,而後將其加入NSOperationQueue;在主線程執行代碼,方法是performSelectorOnMainThread,若是想延時執行代碼能夠用performSelector:onThread:withObject: afterDelay: 或者使用GCD的函數:dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
// 2秒後異步執行這裏的代碼...
});

13.描述一下iOS SDK中如何實現MVC的開發模式

MVC是模型、試圖、控制開發模式,對於iOS SDK,全部的View都是視圖層的,它應該獨立於模型層,由視圖控制層來控制。全部的用戶數據都是模型層,它應該獨立於視圖。全部的ViewController都是控制層,由它負責控制視圖,訪問模型數據。

  1. 你使用過Objective-C的運行時編程(Runtime Programming)麼?若是使用過,你用它作了什麼?你還能記得你所使用的相關的頭文件或者某些方法的名稱嗎?  
    Objecitve-C的重要特性是Runtime(運行時),#import <objc/runtime.h> 下能看到相關的方法,用過objc_getClass()class_copyMethodList()獲取過私有API;使用  
    ```objective-c
    Method method1 = class_getInstanceMethod(cls, sel1);
    Method method2 = class_getInstanceMethod(cls, sel2);
    method_exchangeImplementations(method1, method2);  
    ```   
    代碼交換兩個方法,在寫unit test時使用到。  
    2. 你實現過多線程的Core Data麼?NSPersistentStoreCoordinatorNSManagedObjectContextNSManagedObject中的哪些須要在線程中建立或者傳遞?你是用什麼樣的策略來實現的?  
    沒實現過多線程的CoreData(待實踐
    <!--more--> 
    3. Core開頭的系列的內容。是否使用過CoreAnimationCoreGraphicsUI框架和CACG框架的聯繫是什麼?分別用CACG作過些什麼動畫或者圖像上的內容。(有須要的話還能夠涉及Quartz的一些內容)  
    UI框架的底層有CoreAnimationCoreAnimation的底層有CoreGraphics。    
    UIKit | 
    ------------ | 
    Core Animation | 
    Core Graphics |
    Graphics Hardware|  
    使用CA作過menu菜單的展開收起(太遜了)  
    4. 是否使用過CoreText或者CoreImage等?若是使用過,請談談你使用CoreText或者CoreImage的體驗。
    CoreText能夠解決複雜文字內容排版問題。CoreImage能夠處理圖片,爲其添加各類效果。體驗是很強大,挺複雜的。
    5. NSNotificationKVO的區別和用法是什麼?何時應該使用通知,何時應該使用KVO,它們的實現上有什麼區別嗎?若是用protocoldelegate(或者delegateArray)來實現相似的功能可能嗎?若是可能,會有什麼潛在的問題?若是不能,爲何?(雖然protocoldelegate這種東西面試已經面爛了
    NSNotification是通知模式在iOS的實現,KVO的全稱是鍵值觀察(Key-value observing),其是基於KVCkey-value coding)的,KVC是一個經過屬性名訪問屬性變量的機制。例如將Module層的變化,通知到多個Controller對象時,能夠使用NSNotification;若是是隻須要觀察某個對象的某個屬性,能夠使用KVO
    對於委託模式,在設計模式中是對象適配器模式,其是delegate是指向某個對象的,這是一對一的關係,而在通知模式中,每每是一對多的關係。委託模式,從技術上能夠如今改變delegate指向的對象,但不建議這樣作,會讓人迷惑,若是一個delegate對象不斷改變,指向不一樣的對象。  
    6. 你用過NSOperationQueue麼?若是用過或者瞭解的話,你爲何要使用NSOperationQueue,實現了什麼?請描述它和GCD的區別和相似的地方(提示:能夠從二者的實現機制和適用範圍來描述)。
    使用NSOperationQueue用來管理子類化的NSOperation對象,控制其線程併發數目。GCDNSOperation均可以實現對線程的管理,區別是 NSOperationNSOperationQueue是多線程的面向對象抽象。項目中使用NSOperation的優勢是NSOperation是對線程的高度抽象,在項目中使用它,會使項目的程序結構更好,子類化NSOperation的設計思路,是具備面向對象的優勢(複用、封裝),使得實現是多線程支持,而接口簡單,建議在複雜項目中使用。
    項目中使用GCD的優勢是GCD自己很是簡單、易用,對於不復雜的多線程操做,會節省代碼量,而Block參數的使用,會是代碼更爲易讀,建議在簡單項目中使用。
    更詳細的答案見個人這篇文章
    7. 既然提到GCD,那麼問一下在使用GCD以及block時要注意些什麼?它們兩是一回事兒麼?blockARC中和傳統的MRC中的行爲和用法有沒有什麼區別,須要注意些什麼?如何避免循環引用?
    使用block是要注意,若將block作函數參數時,須要把它放到最後,GCDGrand Central Dispatch,是一個對線程開源類庫,而Block是閉包,是可以讀取其餘函數內部變量的函數。更詳細的答案見個人這篇文章
    8. 您是否作過異步的網絡處理和通信方面的工做?若是有,能具體介紹一些實現策略麼?
    使用NSOperation發送異步網絡請求,使用NSOperationQueue管理線程數目及優先級,底層是用NSURLConnetion,詳細可見開源框架[LWConnetion](https://github.com/xunyn/LWConnetionDemo)。  
    9. 對於Objective-C,你認爲它最大的優勢和最大的不足是什麼?對於不足之處,如今有沒有可用的方法繞過這些不足來實現需求。若是能夠的話,你有沒有考慮或者實踐太重新實現OC的一些功能,若是有,具體會如何作?
    最大的優勢是它的運行時特性,不足是沒有命名空間,對於命名衝突,能夠使用長命名法或特殊前綴解決,若是是引入的第三方庫之間的命名衝突,能夠使用link命令及flag解決衝突。  
    10. 你實現過一個框架或者庫以供別人使用麼?若是有,請談一談構建框架或者庫時候的經驗;若是沒有,請設想和設計框架的publicAPI,並指出大概須要如何作、須要注意一些什麼方面,來使別人容易地使用你的框架。
    抽象和封裝,方便使用。首先是對問題有充分的瞭解,好比構建一個文件解壓壓縮框架,從使用者的角度出發,只需關注發送給框架一個解壓請求,框架完成複雜文件的解壓操做,而且在適當的時候通知給是哦難過者,如解壓完成、解壓出錯等。在框架內部去構建對象的關係,經過抽象讓其更爲健壯、便於更改。其次是API的說明文檔。

 

.關於推送通知

來源:http://blog.csdn.net/enuola/article/details/8627283

推送通知,也被叫作遠程通知,是在iOS 3.0之後被引入的功能。是當程序沒有啓動或不在前臺運行時,告訴用戶有新消息的一種途徑,是從外部服務器發送到應用程序上的。通常說來,當要顯示消息或 下載數據的時候,通知是由遠程服務器(程序的提供者)發送,而後經過蘋果的推送通知服務(Apple Push Notification Service,簡稱apns)推送到設備的程序上。

推送的新消息多是一條信息、一項即將到期的日程或是一份遠程服務器上的新數據。在系統上展示的時候,能夠顯示警告信息或在程序icon上顯示數字,同 時,也能夠播放警告音。一旦用戶注意到程序有新的信息、時間或是數據,他們能夠運行程序並訪問新的內容。也能夠選擇忽略通知,這時程序將不會被激活。

iPhone, iPadiPod touch上同一時刻只有一個app在前臺運行。大多數程序在後臺運行的時候,能夠對某些用戶感興趣的內容作出迴應(定時、或數據等)。推送通知能讓程序在這些事件發生的時候通知用戶。

做爲提供者爲程序開發和部署推送通知,必須經過iOS Developer Program Portal得到SSL證書。每一個證書限用於一個程序,使用程序的bundle ID做爲標識。證書有兩種用途的:一種是針對sandbox(用於開發和測試),另一種針對發佈產品。這兩種運行環境擁有爲各自指定的IP地址而且須要 不一樣的證書。還必須爲兩種不一樣的環境獲取各自的provisioning profiles

APNS提供了兩項基本的服務:消息推送和反饋服務。

消息推送:使用流式TCP套接字將推送通知做爲二進制數據發送給APNs。消息推送有分別針對開發和測試用的sandbox、發佈產品的兩個接口,每一個都 有各自的地址和端口。無論用哪一個接口,都須要經過TLSSSL,使用SSL證書來創建一個安全的信道。提供者編制通知信息,而後經過這個信道將其發送給 APNs
注:sandbox:   gateway.sandbox.push.apple.com:219
產品接口:gateway.push.apple.com:2195

反饋服務:能夠獲得針對某個程序的發送失敗記錄。提供者應該使用反饋服務週期性檢查哪些設備一直收不到通知,不須要重複發送通知到這些設備,下降推送服務器的負擔。
注:sandboxfeedback.push.apple.com:2196
產品接口:feedback.sandbox.push.apple.com:2196

 

.Apple Push Notification的工做機制

下面是一個完整推送流程圖

 從上圖,咱們能夠看到。

  1. 首先是應用程序註冊消息推送。
  2. IOSAPNS ServerdeviceToken。應用程序接受deviceToken
  3. 應用程序將deviceToken發送給PUSH服務端程序(Provider)
  4. 服務端程序向APNS服務發送消息。
  5. APNS服務將消息發送給iPhone應用程序。

不管是iPhone客戶端跟APNS,仍是ProviderAPNS都須要經過證書進行鏈接的:

圖中,

1. Provider是指某個iPhone軟件的Push服務器,是咱們將要開發的服務器。

2. APNS Apple Push Notification ServiceApple Push服務器)的縮寫,是蘋果的服務器。

上圖能夠分爲三個階段:

第一階段:推送服務器(provider)把要發送的消息、目的iPhone的標識打包,發給APNS

第二階段:APNS在自身的已註冊Push服務的iPhone列表中,查找有相應標識的iPhone,並把消息發到iPhone

第三階段:iPhone把發來的消息傳遞給相應的應用程序,而且按照設定彈出Push通知。

 

 

  1. 使用開發者賬號登陸IOS Provisioning ,選擇或新建一個App Id,這裏以「info.luoyl.iostest」爲例
  2. 建立完後,進入App Id列表,能夠看到新建的App Id默認是沒有激活推送功能的,點擊Configure連接,進入推送功能激活頁面: 
  3. 「Enable for Apple Push Notification service」選項上打勾,而後在行點「configure」按鈕:  此時會彈出一窗口,點「continue」
  4. 5. 彈出證書上傳頁面,證書選擇事先作好的「CertificateSigningRequest.certSigningRequest」,而後點「Generate」按鈕;
  5. 6. 接下來會有「Your APNs SSL Certificate has been generated.」提示,點「continue」
  6. 7. 下載剛生成的證書「aps_development.cer」到電腦:
  7. 8. 至此,appidDevelopment Push SSL Certificate已經變成「Enabled」狀態了:
  8. 9. 製做一開發者測試證書,appid指定爲「info.luoyl.iostest」, 下載後雙擊安裝到電腦上
  9. 10. 雙擊在步驟7下載的「aps_development.cer」安裝到keychain Access上:
  10. 11. 選中push Services證書,右鍵導出證書爲我的信息交換(.p12)格式文件,這裏我命名爲「aps_development.p12」,點存儲時會彈出一個密碼設置窗口,可留空不填:
  11. 12. 在終端執行下面的命令,把剛纔導出的我的信息交換(.p12)格式文件加密轉換成推送服務器的推送證書:

 

.開發帶有推送功能的IOS應用

爲使應用能支持推送功能,咱們的項目配置時要注意:

  1. Bundle IdentifierCode Signing指定的開發證書綁定的AppId要和推送證書綁定的AppId一致(見下圖);
  2. 如 果項目中的開發證書在AppId激活推送功能前已經建立了,這時必須從新生成一個。支持推送功能的開發證書會比舊證書多出一項名爲 「aps- environment」的受權串,若是繼續使用舊證書,在程序啓動嘗試註冊推送功能時會出現「 未找到應用程序的「aps-environment」的權利字符串 的錯誤;
  3. 測試須要用真機,模擬器不支持。

 

 

 

 

 

在代碼方面,推送的註冊、監聽和處理都集中在AppDelegate類裏:

1.(BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
在該方法體裏主要實現兩個功能:
一是完成推送功能的註冊請求,即在程序啓動時彈出是否使用推送功能;
二是實現的程序啓動是經過推送消息窗口觸發的,在這裏能夠處理推送內容;

  1. - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions     
  2. {     
  3. self.window = [[[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]] autorelease];     
  4. // Override point for customization after application launch.     
  5. self.viewController = [[[ViewController alloc] init] autorelease];     
  6. self.window.rootViewController = self.viewController;     
  7. [self.window setBackgroundColor:[UIColor colorWithPatternImage:[UIImage imageNamed:@"background.png"]]];     
  8. [self.window makeKeyAndVisible];     
  9. /** 註冊推送通知功能, */    
  10. [[UIApplication sharedApplication] registerForRemoteNotificationTypes:(UIRemoteNotificationTypeAlert | UIRemoteNotificationTypeBadge | UIRemoteNotificationTypeSound)];     
  11. //判斷程序是否是由推送服務完成的     
  12. if (launchOptions) {     
  13. NSDictionary* pushNotificationKey = [launchOptions objectForKey:UIApplicationLaunchOptionsRemoteNotificationKey];     
  14. if (pushNotificationKey) {     
  15. UIAlertView *alert = [[UIAlertView alloc]initWithTitle:@"推送通知"      
  16. message:@"這是經過推送窗口啓動的程序,你能夠在這裏處理推送內容"    
  17. delegate:nil      
  18. cancelButtonTitle:@"知道了"      
  19. otherButtonTitles:nil, nil];     
  20. [alert show];     
  21. [alert release];     
  22. }     
  23. }     
  24. return YES;     
  25. }     


 2. 接收從蘋果服務器返回的惟一的設備token,該token是推送服務器發送推送消息的依據,因此須要發送回推送服務器保存

  1. - (void)application:(UIApplication *)app didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken {     
  2. NSString* token = [NSString stringWithFormat:@"%@",deviceToken];     
  3. NSLog(@"apns -> 生成的devToken:%@", token);     
  4. //deviceToken發送到咱們的推送服務器     
  5. DeviceSender* sender = [[[DeviceSender alloc]initWithDelegate:self ]autorelease];     
  6. [sender sendDeviceToPushServer:token ];         
  7. }     


3.接收註冊推送通知功能時出現的錯誤,並作相關處理:

 

  1. - (void)application:(UIApplication *)app didFailToRegisterForRemoteNotificationsWithError:(NSError *)err {     
  2. NSLog(@"apns -> 註冊推送功能時發生錯誤, 錯誤信息:\n %@", err);     
  3. }    


4. 接收到推送消息,解析處理

 

  1. - (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo     
  2. {     
  3. NSLog(@"\napns -> didReceiveRemoteNotification,Receive Data:\n%@", userInfo);     
  4. //icon上的標記數字設置爲0,     
  5. application.applicationIconBadgeNumber = 0;     
  6. if ([[userInfo objectForKey:@"aps"] objectForKey:@"alert"]!=NULL) {     
  7. UIAlertView* alert = [[UIAlertView alloc] initWithTitle:@"**推送消息**"    
  8. message:[[userInfo objectForKey:@"aps"] objectForKey:@"alert"]     
  9. delegate:self     
  10. cancelButtonTitle:@"關閉"    
  11. otherButtonTitles:@"處理推送內容",nil];     
  12. alert.tag = alert_tag_push;     
  13. [alert show];     
  14. }     
  15. }     

經過上面的代碼,基本推送功能的開發已經完成了。最後附件上面代碼中所需用到的DeviceSender的類文件,須要將其頭文件導入到AppDelegate

  

 

注意:有的App IDApple Push Notification service列是灰色的,而且不容許使用Configure按鈕,這是由於APNS不支持帶通配符的App ID

 

到如今爲止,咱們已經生成了三個文件:

 

1Push.certSigningRequest

2Push.p12

3aps_developer_identity.cer

 

在項目的AppDelegate中的didFinishLaunchingWithOptions方法中加入下面的代碼:

 

  1. [[UIApplication sharedApplication] registerForRemoteNotificationTypes:(UIRemoteNotificationTypeAlert | UIRemoteNotificationTypeSound | UIRemoteNotificationTypeBadge)];   

 

經過registerForRemoteNotificationTypes方法,告訴應用程序,能接受push來的通知。

 

在項目的AppDelegate中添加下面的方法來獲取deviceToken

 

  1. - (void)application:(UIApplication *)app didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken {     
  2. NSString *token = [NSString stringWithFormat:@"%@", deviceToken];  
  3. NSLog(@"My token is:%@", token);  
  4. }  
  5. - (void)application:(UIApplication *)app didFailToRegisterForRemoteNotificationsWithError:(NSError *)error {      
  6. NSString *error_str = [NSString stringWithFormat: @"%@", error];  
  7. NSLog(@"Failed to get token, error:%@", error_str);  
  8. }  

 

獲取到的deviceToken,咱們能夠提交給後臺應用程序,發送通知的後臺應用程序除了須要知道deviceToken以外,還須要一個與APNS鏈接的證書。

 

這個證書能夠經過咱們前面生成的兩個文件中獲得。

 

1、將aps_developer_identity.cer轉換成aps_developer_identity.pem格式

 

  1. openssl x509 -in aps_developer_identity.cer -inform DER -out aps_developer_identity.pem -outform PEM  

 

2、將p12格式的私鑰轉換成pem

 

  1. openssl pkcs12 -nocerts -out Push_Noenc.pem -in Push.p12  

 

3、建立p12文件

 

  1. openssl pkcs12 -export -in aps_developer_identity.pem -inkey Push_Noenc.pem -certfile Push.certSigningRequest -name "aps_developer_identity" -out aps_developer_identity.p12  

 

這樣咱們就獲得了在.netjava等後臺應用程序中使用的證書文件:aps_developer_identity.p12

 

若是後臺應用是php的話,那麼能夠按照 iOS消息推送機制中pem文件的生成這篇文章中的方法來生成php後臺應用程序中使用的證書文件:ck.pem

 

SQLite是嵌入式的和輕量級的sql數據庫。普遍用於包括瀏覽器、iosandroid以及一些便攜需求的小型web應用系統。

SQLiteMySQL的精簡版,無需服務器就能進行;限制條件:必須手動建立數據庫,沒有面向對象的接口;

Demo作了個簡單的保存學生信息的例子,點擊保存按鈕能夠保存信息,點擊查詢能夠查詢信息,Demo下載地址:http://download.csdn.net/detail/weasleyqi/4706760 

 

要想在工程中使用SQLite,須要將SQLite的庫添加到工程:

 

在本工程中的.h文件中引用這個庫:

[css] view plaincopy

  1. <span style="font-size:14px;">#import "sqlite3.h"</span>  

建立數據庫:

接下來若是該數據庫不存在須要建立這個數據庫,建立的過程寫在viewDidLoad裏面:

[css] view plaincopy

  1. <span style="font-size:14px;">- (void)viewDidLoad  
  2. {  
  3. [super viewDidLoad];  
  4. // Do any additional setup after loading the view, typically from a nib.  
  5. NSString *docsDir;  
  6. NSArray *dirPaths;  
  7. dirPaths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);  
  8. docsDir = [dirPaths objectAtIndex:0];  
  9. databasePath = [[NSString alloc] initWithString:[docsDir stringByAppendingPathComponent:@"info.db"]];  
  10. NSFileManager *filemanager = [NSFileManager defaultManager];  
  11. if ([filemanager fileExistsAtPath:databasePath] == NO) {  
  12. const char *dbpath = [databasePath UTF8String];  
  13. if (sqlite3_open(dbpath, &dataBase)==SQLITE_OK) {  
  14. char *errmsg;  
  15. const char *createsql = "CREATE TABLE IF NOT EXISTS INFO (ID INTEGER PRIMARY KEY AUTOINCREMENT, NUM TEXT, CLASSNAME TEXT,NAME TEXT)";  
  16. if (sqlite3_exec(dataBase, createsql, NULL, NULL, &errmsg)!=SQLITE_OK) {  
  17. status.text = @"create table failed.";  
  18. }  
  19. }  
  20. else {  
  21. status.text = @"create/open failed.";  
  22. }  
  23. }  
  24. }</span>  

由於SQLite數據庫是文件數據庫,是保存在文件系統中的,ios下:

  • Documents:應用中用戶數據能夠放在這裏,iTunes備份和恢復的時候會包括此目錄
  • tmp:存放臨時文件,iTunes不會備份和恢復此目錄,此目錄下文件可能會在應用退出後刪除
  • Library/Caches:存放緩存文件,iTunes不會備份此目錄,此目錄下文件不會在應用退出刪除

咱們的數據庫文件是保存在Documents下的。

切記,由於用的是C語法,sqlite3_open傳入的是database的地址!

 

保存信息:

[css] view plaincopy

  1. <span style="font-size:14px;">- (IBAction)saveinfo:(id)sender {  
  2. sqlite3_stmt *statement;  
  3. const char *dbpath = [databasePath UTF8String];  
  4. if (sqlite3_open(dbpath, &dataBase)==SQLITE_OK) {  
  5. if ([num.text isEqualToString:@""]) {  
  6. UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"SORRY!" message:@"number cannot be nil!" delegate:self cancelButtonTitle:@"OK" otherButtonTitles:nil];  
  7. [alert show];  
  8. }  
  9. else {  
  10. NSString *insertSql = [NSString stringWithFormat:@"INSERT INTO INFO (num,classname,name) VALUES(\"%@\",\"%@\",\"%@\")",num.text,classname.text,name.text];  
  11. const char *insertstaement = [insertSql UTF8String];  
  12. sqlite3_prepare_v2(dataBase, insertstaement, -1, &statement, NULL);  
  13. if (sqlite3_step(statement)==SQLITE_DONE) {  
  14. status.text = @"save to DB.";  
  15. num.text = @"";  
  16. classname.text = @"";  
  17. name.text = @"";  
  18. }  
  19. else {  
  20. status.text = @"save failed!";  
  21. }  
  22. sqlite3_finalize(statement);  
  23. sqlite3_close(dataBase);  
  24. }  
  25. }  
  26. }</span>  


在往數據庫裏面插入數據的時候,咱們須要先打開數據庫,而後執行插入語句,結束的時候切記要關閉數據庫!

 

 

查詢操做:

[css] view plaincopy

  1. <span style="font-size:14px;">- (IBAction)searchResult:(id)sender {  
  2. const char *dbpath = [databasePath UTF8String];  
  3. sqlite3_stmt *statement;  
  4. if (sqlite3_open(dbpath, &dataBase)==SQLITE_OK) {  
  5. NSString *querySQL = [NSString stringWithFormat:@"SELECT classname,name from info where num=\"%@\"",num.text];  
  6. const char *querystatement = [querySQL UTF8String];  
  7. if (sqlite3_prepare_v2(dataBase, querystatement, -1, &statement, NULL)==SQLITE_OK) {  
  8. if (sqlite3_step(statement)==SQLITE_ROW) {  
  9. NSString *classnameField = [[NSString alloc] initWithUTF8String:(const char *)sqlite3_column_text(statement, 0)];  
  10. classname.text = classnameField;  
  11. NSString *nameField = [[NSString alloc] initWithUTF8String:(const char *) sqlite3_column_text(statement, 1)];  
  12. name.text = nameField;  
  13. status.text = @"find~~~";                  
  14. }  
  15. else {  
  16. status.text = @"did not find you need.";  
  17. }  
  18. sqlite3_finalize(statement);  
  19. }  
  20. sqlite3_close(dataBase);  
  21. }  
  22. }</span>  


查詢操做一樣也是須要先打開數據庫,再查詢,最後關閉數據庫,在這裏就指定了根據學號來查詢,其餘狀況未涉及。

 

 

在本例中還涉及一個觸摸屏幕來關閉鍵盤:

viewcontroller.h中添加申明代碼:

[css] view plaincopy

  1. <span style="font-size:14px;">- (IBAction)backgroundTap:(id)sender;  
  2. </span>  

經過觸摸屏幕來關閉鍵盤須要咱們的.xib文件的classUIControl,點擊viewController.xib文件,選中view,打開 Identity Inspector,在class中選擇UIConrol,再選擇Connector Inspector,找到Touch Down,把圓圈中的線映射到剛剛的IBAction;

 

viewController.m文件中實現該方法:

[css] view plaincopy

  1. - (IBAction)backgroundTap:(id)sender {  
  2. [num resignFirstResponder];  
  3. [classname resignFirstResponder];  
  4. [name resignFirstResponder];  
  5. }  

這樣,基本上就完成了

 

 

1、離線緩存

在項目開發中,一般都須要對數據進行離線緩存的處理,如新聞數據的離線緩存等。

說明:離線緩存通常都是把數據保存到項目的沙盒中。有如下幾種方式

(1)歸檔:NSCodeing、NSKeyedArchiver

(2)偏好設置:NSUserDefaults

(3)Plist存儲:writeToFile

提示:上述三種方法都有一個致命的缺點,那就是都沒法存儲大批量的數據,有性能的問題。

舉例:使用歸檔

 

兩個問題:

(1)數據的存取都必須是完整的,要求寫入的時候要一次性寫入,讀取的時候要一次性所有讀取,這涉及到應用的性能問題。

(2)若是有1000條數據,此時要把第1001條數據存入,那麼須要把全部的數據取出來,把這條數據加上去以後,再存入。

說明:以上的三種技術不能處理大批量數據的存儲,大批量數據一般使用數據庫來進行存儲。

 

 2、SQLite簡單介紹

1.ios中數據的存儲方式

(1)Plist(NSArray\NSDictionary)

(2)Preference(偏好設置\NSUserDefaults)

(3)NSCoding(NSKeyedArchiver\NSkeyedUnarchiver)

(4)SQLite3

  (5)Core Data

說明:

3是版本號,是SQLite的第三個版本。

core Data是對SQLite的封裝,由於iOS中使用的SQLite是純C語言的。

2.SQLite

(1)什麼是SQLite?

答:SQLite是一款輕型的嵌入式數據庫,安卓和ios開發使用的都是SQLite數據庫

(2)特色(優勢)

  答:1)它佔用資源很是的低,在嵌入式設備中,可能只須要幾百K的內存就夠了

  2)它的處理速度比Mysql、PostgreSQL這兩款著名的數據庫都還快

(3)什麼是數據庫

答:數據庫(Database)是按照數據結構來組織、存儲和管理數據的倉庫

(4)數據庫的分類

答:能夠分爲2大種類

關係型數據庫(主流)和對象型數據庫(直接把內存中的對象塞入到數據庫,對比關係型數據庫而言性能不能很好,效率不高)

(5)經常使用關係型數據庫有哪些?

答:PC端:Oracle、MySQL、SQL Server、Access、DB二、Sybase

  嵌入式\移動客戶端:SQLite

(6)數據庫是如何存儲數據的?

答:數據庫的存儲結構和excel很像,以表(table)爲單位 。表由多個字段(列、屬性、column)組成,表裏面的每一行數據稱爲記錄

 

(7)數據庫存儲數據的步驟?

1)新建一張表(table)

2)添加多個字段(column,列,屬性)

3)添加多行記錄(row,record,每行存放多個字段對應的值)

 

 

1 定位服務

    iOS設備提供三種不一樣定位途徑,蜂窩式移動電話基站定位;WiFi定位,經過查詢一個WiFi路由器的地理位置信息,比較省電;GPS衛星定位,經過3~4顆衛星定位,最爲準確,可是耗電量大。iOS系統若是可以接收GPS信息,那麼設備優先採用GPS,其次是WiFi,最後是基站,開發人員不能選擇哪一種定位方式。

    定位服務使用CoreLocation框架,主要使用CLLocationMananger、CLLocationManangerDelegate和CLLocation三個類,CLLocationMananger是定位服務管理類,獲取設備的位置信息,CLLocationManangerDelegate是代理協議,CLLocation封裝了位置信息。

    這裏要注意,CLLocationManangerDelegate 的locationManager:didUpdateToLocation:fromLocation:方法獲得的座標是火星座標,這個緣由你懂得,因此須要轉換成真實的地理座標。我使用的是一個第三方的CSqlite類,有一個轉換座標的數據庫,你調用就能夠轉換爲正確座標了。

    獲得經緯度後,要進行地理位置信息反編碼,使用CLGeocoder類實現,將地理座標轉換爲地理文字描述信息,這些文字描述信息被封裝在CLPlacemark類中。

    固然給定地理信息的文字描述,也能夠進行地理信息編碼查詢,轉換爲地理座標,也是採用CLGeocoder類。

 

判斷一個座標點是否在一個無規則的多邊形內

 

?

 

//    在範圍內返回1,不在返回0

-(int)mutableBoundConrtolAction:(NSMutableArray *)arrSome:(CLLocationCoordinate2D )myCoordinate4{

    int n=arrSome.count;

    float vertx[n];

    float verty[n];

    for (int i=0; i<arrSome.count; i++) {

//MyPoint類存儲的是經度和緯度

        vertx[i]=((MyPoint *)(arrSome[i])).x;

        verty[i]=((MyPoint *)(arrSome[i])).y;

    }

    if (arrSome.count==0) {

         

        return 1;

    }

    BOOL i=pnpoly(arrSome.count, vertx, verty, myCoordinate4.latitude, myCoordinate4.longitude);

     

     

    if (i) {

        return 1;

    }else{

        return 0;

    }

     

     

    return 1;

}

//多邊形由邊界的座標點所構成的數組組成,參數格式 該數組的count,  多邊形邊界點x座標 的組成的數組,多邊形邊界點y座標 的組成的數組,須要判斷的點的x座標,須要判斷的點的y座標

BOOL pnpoly (int nvert, float *vertx, float *verty, float testx, float testy) {

    int i, j;

    BOOL c=NO;

    for (i = 0, j = nvert-1; i < nvert; j = i++) {

         

        if ( ( (verty[i]>testy) != (verty[j]>testy) ) &&

            (testx < (vertx[j]-vertx[i]) * (testy-verty[i]) / (verty[j]-verty[i]) + vertx[i]) )

            c = !c;

    }

    return c;

}

 

 

 

2 系統地圖

 

    地圖我目前用過系統、百度以及高德,開發人員使用都是差很少的,下面的代碼涉及的類都是高德地圖api提供的類。

    我以前作項目,使用高德地圖,作到後期,項目會出現閃退,後來查出是地圖區域內存的問題,而後從新佈局了地圖區域,使得每個地圖區域可以及時銷燬,雖然閃退週期明顯延長,可是仍是存在,這裏不知道是何緣由,說來慚愧。

 

設置地圖區域

?

1

2

3

4

5

6

7

8

9

-(void)SetMapRegion:(CLLocationCoordinate2D)myCoordinate

{

    MACoordinateRegion theRegion = { {0.0, 0.0 }, { 0.0, 0.0 } };

    theRegion.center=myCoordinate;

    [self.m_map setScrollEnabled:YES];

    theRegion.span.longitudeDelta = 0.01f;

    theRegion.span.latitudeDelta = 0.01f;

    [self.m_map setRegion:theRegion animated:YES];

}

 

平移地圖,上下左右

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

-(void)panMap:(NSString *)direction{

    CLLocationCoordinate2D changeCoordinate=self.m_map.centerCoordinate;

    CGPoint changePoint=[self.m_map convertCoordinate:changeCoordinate toPointToView:self.m_map];

     

    if ([direction isEqualToString:@"up"]) {

        changePoint.y=changePoint.y+50;

         

    }else if ([direction isEqualToString:@"down"]) {

        changePoint.y=changePoint.y-50;

    }else if ([direction isEqualToString:@"left"]) {

        changePoint.x=changePoint.x-50;

    }else if ([direction isEqualToString:@"right"]) {

        changePoint.x=changePoint.x+50;

    }

    changeCoordinate=[self.m_map convertPoint:changePoint toCoordinateFromView:self.m_map];

    [self.m_map setCenterCoordinate:changeCoordinate animated:YES];

}

 

判斷某一個座標點是否在當前地圖區域內

 

?

1

2

3

4

5

6

7

8

9

10

-(void)isAtCurrentRegion:(CLLocationCoordinate2D)coordiante{

     

    CGPoint point=[self.m_map convertCoordinate:coordiante toPointToView:self.view];

    if ((point.x<0)||(point.y<0)||(point.x>WScreen)||(point.y>HScreen)) {

//        若是不在 設置該點爲地圖中心點

        [self SetMapRegion:coordiante];

    }

     

     

}

在地圖上添加標註

 

    系統地圖使用MapKit框架,核心是MKMapView類,顯示地圖只要添加MKMapView實例就能夠了。若是要實如今地圖上添加標註點,第以是觸發添加動做,第二實現MKMapViewDelegate的mapView:viewForAnnotation:完成添加標註。

    高德地圖實現的原理也是同樣的,高德地圖使用的是MAMapKit框架。對於annotation,通常會自定義一個繼承NSobject而且實現了maannotation協議的類,而後使用mapview的addAnnotation:方法就能夠。MKReverseGeocoder類能夠實現coordinate的反編碼,這裏須要實現它的代理,把獲得的地理文字描述信息賦給annotation。這裏須要實現代理的mapView:viewForAnnotation:方法,一個標註其實就是一個MAAnnotationView,標註有點相似tableviewcell,這裏也有重用機制。實現代理的mapView:annotationView:calloutAccessoryControlTapped:方法能夠響應leftCalloutAccessoryView或者rightCalloutAccessoryView的點擊事件,不過這個accessory view必須繼承自UIControl。

 

在地圖上繪製線條和多邊形

 

    MAPolyline類定義一個由多個點相連的多段線,點與點之間尾部想連但第一點與最後一個點不相連, 一般MAPolyline是MAPolylineView的model,它提供了兩個方法polylineWithPoints:count:、polylineWithCoordinates:count:用來添加線條,而後再經過map view的addOverlay:方法把Polyline實例添加進去,最後實現mapviewdelegate的mapView:viewForOverlay:方法就能夠了。注意若是一開始添加的不是coordinate,而是point,能夠經過map view的convertPoint:toCoordinateFromView:方法進行轉換。

    MAPolygon類定義的就是一個不規則的由多個點組成的閉合多邊形,點與點之間按順序尾部相連, 第一個點與最後一個點相連, 一般MAPolygon是MAPolygonView的model,首先須要添加座標點的數組,能夠使用polygonWithCoordinates:count:方法或者polygonWithPoints:count:方法,而後把這個polygon經過addOverlay:方法添加到map view上就能夠了。而後能夠在mapviewdelegate裏面的mapView:viewForOverlay:方法裏面給MAPolygonView的屬性賦值,這樣一個完整的多邊形就出來了。

 

    無論是高德地圖仍是百度地圖等第三方,都會有一個mapsearchkit,這是一個用於查詢的框架,有興趣的朋友能夠多加研究。

 

 

iOS中的MapKit集成了google地圖api的不少功能加上iOS的定位的功能,咱們就能夠實現將你運行的軌跡繪製到地圖上面。這個功能很是有用,好比快遞追蹤、汽車的gprs追蹤、人員追蹤等等。這篇文章咱們將使用Map KitiOS的定位功能,將你的運行軌跡繪製在地圖上面。

實現

   在以前的一篇文章描述瞭如何在地圖上顯示本身的位置,若是咱們將這些位置先保存起來,而後串聯起來繪製到地圖上面,那就是咱們的運行軌跡了。

    首先咱們看下如何在地圖上繪製曲線。在Map Kit中提供了一個叫MKPolyline的類,咱們能夠利用它來繪製曲線,先看個簡單的例子。

    使用下面代碼從一個文件中讀取出經緯度,而後建立一個路徑:MKPolyline實例。

[plain] view plaincopy

  1. -(void) loadRoute 
  2. NSString* filePath = [[NSBundle mainBundle] pathForResource:@」route」 ofType:@」csv」]; 
  3. NSString* fileContents = [NSString stringWithContentsOfFile:filePath encoding:NSUTF8StringEncoding error:nil]; 
  4. NSArray* pointStrings = [fileContents componentsSeparatedByCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]]; 
  5. // while we create the route points, we will also be calculating the bounding box of our route 
  6. // so we can easily zoom in on it. 
  7. MKMapPoint northEastPoint; 
  8. MKMapPoint southWestPoint;  
  9. // create a c array of points. 
  10. MKMapPoint* pointArr = malloc(sizeof(CLLocationCoordinate2D) * pointStrings.count); 
  11. for(int idx = 0; idx < pointStrings.count; idx++) 
  12. // break the string down even further to latitude and longitude fields. 
  13. NSString* currentPointString = [pointStrings objectAtIndex:idx]; 
  14. NSArray* latLonArr = [currentPointString componentsSeparatedByCharactersInSet:[NSCharacterSet characterSetWithCharactersInString:@","]]; 
  15. CLLocationDegrees latitude = [[latLonArr objectAtIndex:0] doubleValue]; 
  16. CLLocationDegrees longitude = [[latLonArr objectAtIndex:1] doubleValue]; 
  17. // create our coordinate and add it to the correct spot in the array 
  18. CLLocationCoordinate2D coordinate = CLLocationCoordinate2DMake(latitude, longitude); 
  19. MKMapPoint point = MKMapPointForCoordinate(coordinate); 
  20. // 
  21. // adjust the bounding box 
  22. // 
  23. // if it is the first point, just use them, since we have nothing to compare to yet. 
  24. if (idx == 0) { 
  25. northEastPoint = point; 
  26. southWestPoint = point; 
  27. else 
  28. if (point.x > northEastPoint.x) 
  29. northEastPoint.x = point.x; 
  30. if(point.y > northEastPoint.y) 
  31. northEastPoint.y = point.y; 
  32. if (point.x < southWestPoint.x) 
  33. southWestPoint.x = point.x; 
  34. if (point.y < southWestPoint.y) 
  35. southWestPoint.y = point.y; 
  36. pointArr[idx] = point; 
  37. // create the polyline based on the array of points. 
  38. self.routeLine = [MKPolyline polylineWithPoints:pointArr count:pointStrings.count]; 
  39. _routeRect = MKMapRectMake(southWestPoint.x, southWestPoint.y, northEastPoint.x - southWestPoint.x, northEastPoint.y - southWestPoint.y);
  40. // clear the memory allocated earlier for the points 
  41. free(pointArr); 
  42. }  

[plain] view plaincopy

  1. -(void) loadRoute  
  2. {  
  3. NSString* filePath = [[NSBundle mainBundle] pathForResource:@」route」 ofType:@」csv」];  
  4. NSString* fileContents = [NSString stringWithContentsOfFile:filePath encoding:NSUTF8StringEncoding error:nil];  
  5. NSArray* pointStrings = [fileContents componentsSeparatedByCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];  
  6. // while we create the route points, we will also be calculating the bounding box of our route  
  7. // so we can easily zoom in on it.  
  8. MKMapPoint northEastPoint;  
  9. MKMapPoint southWestPoint;   
  10. // create a c array of points.  
  11. MKMapPoint* pointArr = malloc(sizeof(CLLocationCoordinate2D) * pointStrings.count);  
  12. for(int idx = 0; idx < pointStrings.count; idx++)  
  13. {  
  14. // break the string down even further to latitude and longitude fields.  
  15. NSString* currentPointString = [pointStrings objectAtIndex:idx];  
  16. NSArray* latLonArr = [currentPointString componentsSeparatedByCharactersInSet:[NSCharacterSet characterSetWithCharactersInString:@","]];  
  17. CLLocationDegrees latitude = [[latLonArr objectAtIndex:0] doubleValue];  
  18. CLLocationDegrees longitude = [[latLonArr objectAtIndex:1] doubleValue];  
  19. // create our coordinate and add it to the correct spot in the array  
  20. CLLocationCoordinate2D coordinate = CLLocationCoordinate2DMake(latitude, longitude);  
  21. MKMapPoint point = MKMapPointForCoordinate(coordinate);  
  22. //  
  23. // adjust the bounding box  
  24. //  
  25. // if it is the first point, just use them, since we have nothing to compare to yet.  
  26. if (idx == 0) {  
  27. northEastPoint = point;  
  28. southWestPoint = point;  
  29. }  
  30. else  
  31. {  
  32. if (point.x > northEastPoint.x)  
  33. northEastPoint.x = point.x;  
  34. if(point.y > northEastPoint.y)  
  35. northEastPoint.y = point.y;  
  36. if (point.x < southWestPoint.x)  
  37. southWestPoint.x = point.x;  
  38. if (point.y < southWestPoint.y)  
  39. southWestPoint.y = point.y;  
  40. }  
  41. pointArr[idx] = point;  
  42. }  
  43. // create the polyline based on the array of points.  
  44. self.routeLine = [MKPolyline polylineWithPoints:pointArr count:pointStrings.count];  
  45. _routeRect = MKMapRectMake(southWestPoint.x, southWestPoint.y, northEastPoint.x - southWestPoint.x, northEastPoint.y - southWestPoint.y);  
  46. // clear the memory allocated earlier for the points  
  47. free(pointArr);  
  48. }   

 

將這個路徑添加到地圖上

[plain] view plaincopy

  1. [self.mapView addOverlay:self.routeLine];  

[plain] view plaincopy

  1. [self.mapView addOverlay:self.routeLine];   

 

顯示在地圖上:

[plain] view plaincopy

  1. - (MKOverlayView *)mapView:(MKMapView *)mapView viewForOverlay:(id )overlay 
  2. MKOverlayView* overlayView = nil; 
  3. if(overlay == self.routeLine) 
  4. //if we have not yet created an overlay view for this overlay, create it now. 
  5. if(nil == self.routeLineView) 
  6. self.routeLineView = [[[MKPolylineView alloc] initWithPolyline:self.routeLine] autorelease]; 
  7. self.routeLineView.fillColor = [UIColor redColor]; 
  8. self.routeLineView.strokeColor = [UIColor redColor]; 
  9. self.routeLineView.lineWidth = 3; 
  10. overlayView = self.routeLineView; 
  11. return overlayView; 
  12. }  

[plain] view plaincopy

  1. - (MKOverlayView *)mapView:(MKMapView *)mapView viewForOverlay:(id )overlay  
  2. {  
  3. MKOverlayView* overlayView = nil;  
  4. if(overlay == self.routeLine)  
  5. {  
  6. //if we have not yet created an overlay view for this overlay, create it now.  
  7. if(nil == self.routeLineView)  
  8. {  
  9. self.routeLineView = [[[MKPolylineView alloc] initWithPolyline:self.routeLine] autorelease];  
  10. self.routeLineView.fillColor = [UIColor redColor];  
  11. self.routeLineView.strokeColor = [UIColor redColor];  
  12. self.routeLineView.lineWidth = 3;  
  13. }  
  14. overlayView = self.routeLineView;  
  15. }  
  16. return overlayView;  
  17. }   

效果:

而後咱們在從文件中讀取位置的方法改爲從用gprs等方法獲取當前位置。

第一步:建立一個CLLocationManager實例

第二步:設置CLLocationManager實例委託和精度

第三步:設置距離篩選器distanceFilter

第四步:啓動請求

代碼以下:

[plain] view plaincopy

  1. - (void)viewDidLoad { 
  2. [super viewDidLoad]; 
  3. noUpdates = 0; 
  4. locations = [[NSMutableArray alloc] init]; 
  5. locationMgr = [[CLLocationManager alloc] init]; 
  6. locationMgr.delegate = self; 
  7. locationMgr.desiredAccuracy =kCLLocationAccuracyBest; 
  8. locationMgr.distanceFilter  = 1.0f; 
  9. [locationMgr startUpdatingLocation]; 

[plain] view plaincopy

  1. - (void)viewDidLoad {  
  2. [super viewDidLoad];  
  3. noUpdates = 0;  
  4. locations = [[NSMutableArray alloc] init];  
  5. locationMgr = [[CLLocationManager alloc] init];  
  6. locationMgr.delegate = self;  
  7. locationMgr.desiredAccuracy =kCLLocationAccuracyBest;  
  8. locationMgr.distanceFilter  = 1.0f;  
  9. [locationMgr startUpdatingLocation];  
  10. }  


上面的代碼我定義了一個數組,用於保存運行軌跡的經緯度。

每次通知更新當前位置的時候,咱們將當前位置的經緯度放到這個數組中,並從新繪製路徑,代碼以下:

[plain] view plaincopy

  1. - (void)locationManager:(CLLocationManager *)manager  
  2. didUpdateToLocation:(CLLocation *)newLocation  
  3. fromLocation:(CLLocation *)oldLocation{ 
  4. noUpdates++; 
  5. [locations addObject: [NSString stringWithFormat:@"%f,%f",[newLocation coordinate].latitude, [newLocation coordinate].longitude]]; 
  6. [self updateLocation]; 
  7. if (self.routeLine!=nil) { 
  8. self.routeLine =nil; 
  9. if(self.routeLine!=nil) 
  10. [self.mapView removeOverlay:self.routeLine]; 
  11. self.routeLine =nil; 
  12. // create the overlay 
  13. [self loadRoute]; 
  14. // add the overlay to the map 
  15. if (nil != self.routeLine) { 
  16. [self.mapView addOverlay:self.routeLine]; 
  17. // zoom in on the route.  
  18. [self zoomInOnRoute]; 

[plain] view plaincopy

  1. - (void)locationManager:(CLLocationManager *)manager   
  2. didUpdateToLocation:(CLLocation *)newLocation   
  3. fromLocation:(CLLocation *)oldLocation{  
  4. noUpdates++;  
  5. [locations addObject: [NSString stringWithFormat:@"%f,%f",[newLocation coordinate].latitude, [newLocation coordinate].longitude]];  
  6. [self updateLocation];  
  7. if (self.routeLine!=nil) {  
  8. self.routeLine =nil;  
  9. }  
  10. if(self.routeLine!=nil)  
  11. [self.mapView removeOverlay:self.routeLine];  
  12. self.routeLine =nil;  
  13. // create the overlay  
  14. [self loadRoute];  
  15. // add the overlay to the map  
  16. if (nil != self.routeLine) {  
  17. [self.mapView addOverlay:self.routeLine];  
  18. }  
  19. // zoom in on the route.   
  20. [self zoomInOnRoute];  
  21. }  


咱們將前面從文件獲取經緯度建立軌跡的代碼修改爲從這個數組中取值就好了:

[plain] view plaincopy

  1. // creates the route (MKPolyline) overlay 
  2. -(void) loadRoute 
  3. // while we create the route points, we will also be calculating the bounding box of our route 
  4. // so we can easily zoom in on it.  
  5. MKMapPoint northEastPoint;  
  6. MKMapPoint southWestPoint;  
  7. // create a c array of points.  
  8. MKMapPoint* pointArr = malloc(sizeof(CLLocationCoordinate2D) * locations.count); 
  9. for(int idx = 0; idx < locations.count; idx++) 
  10. // break the string down even further to latitude and longitude fields.  
  11. NSString* currentPointString = [locations objectAtIndex:idx]; 
  12. NSArray* latLonArr = [currentPointString componentsSeparatedByCharactersInSet:[NSCharacterSet characterSetWithCharactersInString:@","]]; 
  13. CLLocationDegrees latitude  = [[latLonArr objectAtIndex:0] doubleValue]; 
  14. CLLocationDegrees longitude = [[latLonArr objectAtIndex:1] doubleValue]; 
  15. CLLocationCoordinate2D coordinate = CLLocationCoordinate2DMake(latitude, longitude); 
  16. MKMapPoint point = MKMapPointForCoordinate(coordinate); 
  17. if (idx == 0) { 
  18. northEastPoint = point; 
  19. southWestPoint = point; 
  20. else  
  21. if (point.x > northEastPoint.x)  
  22. northEastPoint.x = point.x; 
  23. if(point.y > northEastPoint.y) 
  24. northEastPoint.y = point.y; 
  25. if (point.x < southWestPoint.x)  
  26. southWestPoint.x = point.x; 
  27. if (point.y < southWestPoint.y)  
  28. southWestPoint.y = point.y; 
  29. pointArr[idx] = point; 
  30. self.routeLine = [MKPolyline polylineWithPoints:pointArr count:locations.count]; 
  31. _routeRect = MKMapRectMake(southWestPoint.x, southWestPoint.y, northEastPoint.x - southWestPoint.x, northEastPoint.y - southWestPoint.y); 
  32. free(pointArr); 

[plain] view plaincopy

  1. // creates the route (MKPolyline) overlay  
  2. -(void) loadRoute  
  3. {  
  4. // while we create the route points, we will also be calculating the bounding box of our route  
  5. // so we can easily zoom in on it.   
  6. MKMapPoint northEastPoint;   
  7. MKMapPoint southWestPoint;   
  8. // create a c array of points.   
  9. MKMapPoint* pointArr = malloc(sizeof(CLLocationCoordinate2D) * locations.count);  
  10. for(int idx = 0; idx < locations.count; idx++)  
  11. {  
  12. // break the string down even further to latitude and longitude fields.   
  13. NSString* currentPointString = [locations objectAtIndex:idx];  
  14. NSArray* latLonArr = [currentPointString componentsSeparatedByCharactersInSet:[NSCharacterSet characterSetWithCharactersInString:@","]];  
  15. CLLocationDegrees latitude  = [[latLonArr objectAtIndex:0] doubleValue];  
  16. CLLocationDegrees longitude = [[latLonArr objectAtIndex:1] doubleValue];  
  17. CLLocationCoordinate2D coordinate = CLLocationCoordinate2DMake(latitude, longitude);  
  18. MKMapPoint point = MKMapPointForCoordinate(coordinate);  
  19. if (idx == 0) {  
  20. northEastPoint = point;  
  21. southWestPoint = point;  
  22. }  
  23. else   
  24. {  
  25. if (point.x > northEastPoint.x)   
  26. northEastPoint.x = point.x;  
  27. if(point.y > northEastPoint.y)  
  28. northEastPoint.y = point.y;  
  29. if (point.x < southWestPoint.x)   
  30. southWestPoint.x = point.x;  
  31. if (point.y < southWestPoint.y)   
  32. southWestPoint.y = point.y;  
  33. }  
  34. pointArr[idx] = point;  
  35. }  
  36. self.routeLine = [MKPolyline polylineWithPoints:pointArr count:locations.count];  
  37. _routeRect = MKMapRectMake(southWestPoint.x, southWestPoint.y, northEastPoint.x - southWestPoint.x, northEastPoint.y - southWestPoint.y);  
  38. free(pointArr);  
  39. }  


這樣咱們就將咱們運行得軌跡繪製google地圖上面了。

擴展:

    若是你想使用其餘的地圖,好比百度地圖,其實也很方便。能夠將百度地圖放置到UIWebView中間,經過用js去繪製軌跡。

相關文章
相關標籤/搜索