ios網絡編程

b36g 9年前發布 | 2K 次閱讀 Objective-C IOS

一:確認網絡環境3G/WIFI 
 
    1. 添加源文件和framework 
     
    開發Web等網絡應用程序的時候,需要確認網絡環境,連接情況等信息。如果沒有處理它們,是不會通過Apple的審查的。 
    Apple 的 例程 Reachability 中介紹了取得/檢測網絡狀態的方法。要在應用程序程序中使用Reachability,首先要完成如下兩部: 
     
    1.1. 添加源文件: 
    在你的程序中使用 Reachability 只須將該例程中的 Reachability.h 和 Reachability.m 拷貝到你的工程中。如下圖: 
 
     
     
    1.2.添加framework: 
    將SystemConfiguration.framework 添加進工程。如下圖: 
     
     
    2. 網絡狀態 
     
    Reachability.h中定義了三種網絡狀態: 
    typedef enum { 
        NotReachable = 0,            //無連接 
        ReachableViaWiFi,            //使用3G/GPRS網絡 
        ReachableViaWWAN            //使用WiFi網絡 
    } NetworkStatus; 
     
    因此可以這樣檢查網絡狀態: 
 
    Reachability r = [Reachability reachabilityWithHostName:@“ www.apple.com”]; 
    switch ([r currentReachabilityStatus]) { 
            case NotReachable: 
                    // 沒有網絡連接 
                    break; 
            case ReachableViaWWAN: 
                    // 使用3G網絡 
                    break; 
            case ReachableViaWiFi: 
                    // 使用WiFi網絡 
                    break; 
    } 
     
    3.檢查當前網絡環境 
    程序啟動時,如果想檢測可用的網絡環境,可以像這樣 
    // 是否wifi 
    + (BOOL) IsEnableWIFI { 
        return ([[Reachability reachabilityForLocalWiFi] currentReachabilityStatus] != NotReachable); 
    } 
 
    // 是否3G 
    + (BOOL) IsEnable3G { 
        return ([[Reachability reachabilityForInternetConnection] currentReachabilityStatus] != NotReachable); 
    } 
    例子: 
    - (void)viewWillAppear:(BOOL)animated {     
    if (([Reachability reachabilityForInternetConnection].currentReachabilityStatus == NotReachable) &&  
            ([Reachability reachabilityForLocalWiFi].currentReachabilityStatus == NotReachable)) { 
            self.navigationItem.hidesBackButton = YES; 
            [self.navigationItem setLeftBarButtonItem:nil animated:NO]; 
        } 
    } 
 
    4. 鏈接狀態的實時通知 
    網絡連接狀態的實時檢查,通知在網絡應用中也是十分必要的。接續狀態發生變化時,需要及時地通知用戶: 
     
    Reachability 1.5版本 
    // My.AppDelegate.h 
    #import "Reachability.h" 
 
     @interface MyAppDelegate : NSObject <UIApplicationDelegate> { 
        NetworkStatus remoteHostStatus; 
    } 
 
    @property NetworkStatus remoteHostStatus; 
 
    @end 
 
    // My.AppDelegate.m 
    #import "MyAppDelegate.h" 
 
    @implementation MyAppDelegate 
    @synthesize remoteHostStatus; 
 
    // 更新網絡狀態 
    - (void)updateStatus { 
        self.remoteHostStatus = [[Reachability sharedReachability] remoteHostStatus]; 
    } 
 
    // 通知網絡狀態 
    - (void)reachabilityChanged:(NSNotification
)note { 
        [self updateStatus]; 
        if (self.remoteHostStatus == NotReachable) { 
            UIAlertView alert = [[UIAlertView alloc] initWithTitle:NSLocalizedString(@"AppName", nil) 
                         message:NSLocalizedString (@"NotReachable", nil) 
                        delegate:nil cancelButtonTitle:@"OK" otherButtonTitles: nil]; 
            [alert show]; 
            [alert release]; 
        } 
    } 
 
    // 程序啟動器,啟動網絡監視 
    - (void)applicationDidFinishLaunching:(UIApplication
)application { 
     
        // 設置網絡檢測的站點 
        [[Reachability sharedReachability] setHostName:@"www.apple.com"]; 
        [[Reachability sharedReachability] setNetworkStatusNotificationsEnabled:YES]; 
        // 設置網絡狀態變化時的通知函數 
        [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(reachabilityChanged:) 
                                                 name:@"kNetworkReachabilityChangedNotification" object:nil]; 
        [self updateStatus]; 
    } 
 
    - (void)dealloc { 
        // 刪除通知對象 
        [[NSNotificationCenter defaultCenter] removeObserver:self]; 
        [window release]; 
        [super dealloc]; 
    }  
     
    Reachability 2.0版本 
     
 
    // MyAppDelegate.h 
    @class Reachability; 
 
        @interface MyAppDelegate : NSObject <UIApplicationDelegate> { 
            Reachability  hostReach; 
        } 
 
    @end 
 
    // MyAppDelegate.m 
    - (void)reachabilityChanged:(NSNotification
)note { 
        Reachability curReach = [note object]; 
        NSParameterAssert([curReach isKindOfClass: [Reachability class]]); 
        NetworkStatus status = [curReach currentReachabilityStatus]; 
     
        if (status == NotReachable) { 
            UIAlertView
alert = [[UIAlertView alloc] initWithTitle:@"AppName"" 
                              message:@"NotReachable" 
                              delegate:nil 
                              cancelButtonTitle:@"YES" otherButtonTitles:nil]; 
                              [alert show]; 
                              [alert release]; 
        } 
    } 
                               
    - (void)applicationDidFinishLaunching:(UIApplication )application { 
        // ... 
                   
        // 監測網絡情況 
        [[NSNotificationCenter defaultCenter] addObserver:self 
                              selector:@selector(reachabilityChanged:) 
                              name: kReachabilityChangedNotification 
                              object: nil]; 
        hostReach = [[Reachability reachabilityWithHostName:@"www.google.com"] retain]; 
        hostReach startNotifer]; 
        // ... 
    } 
 
 
二:使用NSConnection下載數據 
     
    1.創建NSConnection對象,設置委托對象 
     
    NSMutableURLRequest
request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:[self urlString]]]; 
    [NSURLConnection connectionWithRequest:request delegate:self]; 
     
    2. NSURLConnection delegate委托方法 
        - (void)connection:(NSURLConnection )connection didReceiveResponse:(NSURLResponse )response;   
        - (void)connection:(NSURLConnection )connection didFailWithError:(NSError )error;   
        - (void)connection:(NSURLConnection )connection didReceiveData:(NSData )data;   
        - (void)connectionDidFinishLoading:(NSURLConnection )connection;   
 
    3. 實現委托方法 
    - (void)connection:(NSURLConnection
)connection didReceiveResponse:(NSURLResponse )response { 
        // store data 
        [self.receivedData setLength:0];            //通常在這里先清空接受數據的緩存 
    } 
     
    - (void)connection:(NSURLConnection
)connection didReceiveData:(NSData )data { 
           /
appends the new data to the received data
        [self.receivedData appendData:data];        //可能多次收到數據,把新的數據添加在現有數據最后 
    } 
 
    - (void)connection:(NSURLConnection
)connection didFailWithError:(NSError )error { 
        // 錯誤處理 
    } 
 
    - (void)connectionDidFinishLoading:(NSURLConnection
)connection { 
        // disconnect 
        [UIApplication sharedApplication].networkActivityIndicatorVisible = NO;    
        NSString returnString = [[NSString alloc] initWithData:self.receivedData encoding:NSUTF8StringEncoding]; 
        NSLog(returnString); 
        [self urlLoaded:[self urlString] data:self.receivedData]; 
        firstTimeDownloaded = YES; 
    } 
 
三:使用NSXMLParser解析xml文件 
 
    1. 設置委托對象,開始解析 
    NSXMLParser
parser = [[NSXMLParser alloc] initWithData:data];   //或者也可以使用initWithContentsOfURL直接下載文件,但是有一個原因不這么做: 
    // It's also possible to have NSXMLParser download the data, by passing it a URL, but this is not desirable 
    // because it gives less control over the network, particularly in responding to connection errors. 
    [parser setDelegate:self]; 
    [parser parse]; 
 
    2. 常用的委托方法 
    - (void)parser:(NSXMLParser )parser didStartElement:(NSString )elementName  
                                namespaceURI:(NSString )namespaceURI 
                                qualifiedName:(NSString
)qName  
                                attributes:(NSDictionary )attributeDict; 
    - (void)parser:(NSXMLParser
)parser didEndElement:(NSString )elementName  
                                namespaceURI:(NSString
)namespaceURI  
                                qualifiedName:(NSString )qName; 
    - (void)parser:(NSXMLParser
)parser foundCharacters:(NSString )string; 
    - (void)parser:(NSXMLParser
)parser parseErrorOccurred:(NSError )parseError; 
 
    static NSString
feedURLString = @"http://www.yifeiyang.net/test/test.xml";&nbsp;
 
    3.  應用舉例 
    - (void)parseXMLFileAtURL:(NSURL )URL parseError:(NSError **)error 
    { 
        NSXMLParser
parser = [[NSXMLParser alloc] initWithContentsOfURL:URL]; 
        [parser setDelegate:self]; 
        [parser setShouldProcessNamespaces:NO]; 
        [parser setShouldReportNamespacePrefixes:NO]; 
        [parser setShouldResolveExternalEntities:NO]; 
        [parser parse]; 
        NSError parseError = [parser parserError]; 
        if (parseError && error) { 
            
error = parseError; 
        } 
        [parser release]; 
    } 
 
    - (void)parser:(NSXMLParser )parser didStartElement:(NSString )elementName namespaceURI:(NSString )namespaceURI  
                                        qualifiedName:(NSString
)qName attributes:(NSDictionary )attributeDict{ 
        // 元素開始句柄 
        if (qName) { 
            elementName = qName; 
        } 
        if ([elementName isEqualToString:@"user"]) { 
            // 輸出屬性值 
            NSLog(@"Name is %@ , Age is %@", [attributeDict objectForKey:@"name"], [attributeDict objectForKey:@"age"]); 
        } 
    } 
 
    - (void)parser:(NSXMLParser
)parser didEndElement:(NSString )elementName namespaceURI:(NSString )namespaceURI  
                                        qualifiedName:(NSString )qName 
    { 
        // 元素終了句柄 
        if (qName) { 
               elementName = qName; 
        } 
    } 
 
    - (void)parser:(NSXMLParser
)parser foundCharacters:(NSString )string 
    { 
        // 取得元素的text 
    } 
 
    NSError
parseError = nil; 

    [self parseXMLFileAtURL:[NSURL URLWithString:feedURLString] parseError:&parseError];


使用NSOperation和NSOperationQueue啟動多線程
在app store中的很多應用程序非常的笨重,他們有好的界面,但操作性很差,比如說當程序從網上或本地載入數據的時候,界面被凍結了,用戶只能等程序完全載入數據之后才能進行操作。 
當 打開一個應用程序時,iphone會產生一個包含main方法的線程,所用程序中的界面都是運行在這個線程之中的(table views, tab bars, alerts…),有時候我們會用數據填充這些view,現在問        題是如何有效的載入數據,并且用戶還能自如的操作程序。方法是啟動新的線 程,專門用于數據的下載,而主線程不會因為下載數據被阻塞。 
不管使用任何編程語言,在實現多線程時都是一件很麻煩的事情。更糟糕的是,一旦出 錯,這種錯誤通常相當糟糕。然而,幸運的是apple從os x10.5在這方面做了很多的改進,NSThread的引入,使得開發多線程應用程序容易多了。除此之外,它們還引入了兩個全新的 類,NSOperation和NSOperationQueue。 
接下來我們通過一個實例來剖析如何使用這兩個類實現多線程。這里指示展示這兩個類的基本用法,當然這不是使用他們的唯一辦法。 
如 果你熟悉java或者它的別的變種語言的話 ,你會發現NSOperation對象很像java.lang.Runnable接口,就像java.lang.Runnable接口那 樣,NSOperation類也被設計為可擴展的,而且只有一個需要重寫的方法。它就是-(void)main。使用NSOperation的最簡單的方 式就是把一個NSOperation對象加入到NSOperationQueue隊列中,一旦這個對象被加入到隊列,隊列就開始處理這個對象,直到這個對 象的所有操作完成。然后它被隊列釋放。 
下面的例子中,使用一個獲取網頁,并對其解析程NSXMLDocument,最后將解析得到的NSXMLDocument返回給主線程。 
     
PageLoadOperation.h@interface PageLoadOperation : NSOperation { 
    NSURL targetURL;} 
@property(retain) NSURL
targetURL; 
- (id)initWithURL:(NSURL)url;@end 
 
PageLoadOperation.m 
#import "PageLoadOperation.h"#import "AppDelegate.h"@implementation PageLoadOperation@synthesize targetURL;- (id)initWithURL:(NSURL
)url;{ 
    if (![super init]) return nil; 
    [self setTargetURL:url]; 
    return self;}- (void)dealloc { 
    [targetURL release], targetURL = nil; 
    [super dealloc]; 

- (void)main  

    NSString webpageString = [[[NSString alloc] 
    initWithContentsOfURL:[self targetURL]] autorelease]; 
    NSError
error = nil; 
    NSXMLDocument document = [[NSXMLDocument alloc] 
    initWithXMLString:webpageString  
    options:NSXMLDocumentTidyHTML error:&error]; 
    if (!document) { 
        NSLog(@"%s Error loading document (%@): %@",  
        _cmd, [[self targetURL] absoluteString], error); 
         return; 
    } 
    [[AppDelegate shared] 
    performSelectorOnMainThread:@selector(pageLoaded:) 
         withObject:document waitUntilDone:YES]; 
    [document release]; 

@end 
    正 如我們所看到的那樣,這個類相當的簡單,在它的init方法中接受一個url并保存起來,當main函數被調用的時候,它使用這個保存的url創建一個字 符串,并將這個字符串傳遞給NSXMLDocumentinit方法。如果加載的xml數據沒有出錯,數據會被傳遞給AppDelegate,它處于主線 程中。到此,這個線程的任務就完成了。在主線程中注銷操作隊列的時候,會將這個NSOperation對象釋放。 
AppDelegate.h 
@interface AppDelegate : NSObject { 
    NSOperationQueue
queue; 
}+ (id)shared;- (void)pageLoaded:(NSXMLDocument)document;@endAppDelegate.m        #import "AppDelegate.h"#import "PageLoadOperation.h"@implementation AppDelegate 
static AppDelegate
shared; 
static NSArray urlArray; 
- (id)init 

    if (shared) 
    { 
        [self autorelease]; 
        return shared; 
    } 
    if (![super init]) return nil;    NSMutableArray
array = [[NSMutableArray alloc] init];[array addObject:@"http://www.google.com"];[array addObject:@"http://www.apple.com"];[array addObject:@"http://www.yahoo.com"];[array addObject:@"http://www.zarrastudios.com"];[array addObject:@"http://www.macosxhints.com"];urlArray = array;    queue = [[NSOperationQueue alloc] init];shared = self;return self; 
    } 
    ?    (void)applicationDidFinishLaunching: 
    (NSNotification )aNotification 

        for (NSString
urlString in urlArray)  
        { 
        NSURL url =  
        [NSURL URLWithString:urlString];        PageLoadOperation
plo =  
        [[PageLoadOperation alloc] initWithURL:url]; 
        [queue addOperation:plo]; 
        [plo release]; 
        } 

- (void)dealloc 

        [queue release], queue = nil; 
        [super dealloc]; 

+ (id)shared; 

        if (!shared) { 
            [[AppDelegate alloc] init]; 
        } 
        return shared; 

- (void)pageLoaded:(NSXMLDocument*)document; 

        NSLog(@"%s Do something with the XMLDocument: %@", 
             _cmd, document); 

@end 
 
NSOperationQueue的并行控制(NSOperationQueue Concurrency) 
        在 上面這個簡單的例子中,我們很難看出這些操作是并行運行的,然而,如果你你的操作花費的時間遠遠比這里的要長,你將會發現,隊列是同時執行這些操作的。幸 運的是,如果你想要為隊列限制同時只能運行幾個操作,你可以使用NSOperationQueue的 setMaxConcurrentOperationCount:方法。例如,[queue setMaxConcurrentOperationCount:2];

 本文由用戶 b36g 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!