ASIHTTPRequest 筆記

ASIHTTPRequest 是 Objective-C 上知名的專門用來處理 HTTP requests 的框架,不過,作者似乎已經停止更新了(但是在 iOS 5 還是運作得很正常)。前陣子發現另一個 network framework 叫 AFNetworking,似乎挺不錯的,有空再去試試,雖然我最近寫 mobile app 已經寫到有點煩了…… AFNetworking 是 Gowalla 團隊開發的,對,就是那個被 Facebook 收購然後淒慘地關站的 Gowalla。

Add To Your Xcode Project

詳見:Using ASIHTTPRequest in an iOS project

直接在 Finder 中把 ASIHTTPRequest 的檔案包含目錄拉進 xcode 裡,然後選擇 “Create groups for any added folders”,目錄的結構會像這樣:

ASINetworkQueue

我通常會在每個 view controller 裡面放一個 ASINetworkQueue 物件,由它來統一處理這個頁面的所有 requests。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
- (void)viewDidLoad
{
    [super viewDidLoad];

    requestQueue = [[ASINetworkQueue alloc] init];

    // count = 1,就算是非同步,也會是序列執行
    requestQueue.maxConcurrentOperationCount = 15;

    // ASIHTTPRequest 默認的情況下,queue 中只要有一個 request fail 了,整個 queue 裡的所有 requests 也都會被 cancel 掉
    [requestQueue setShouldCancelAllRequestsOnFailure:NO];

    // go 只需要執行一次
    [requestQueue go];
}

- (void)viewWillDisappear:(BOOL)animated
{
    [super viewWillDisappear:animated];

    // 離開這個頁面就暫停所有的 requests,之後又回到這個頁面時,可以繼續未完成的請求
    [self.requestQueue setSuspended:YES];
}

- (void)viewWillAppear:(BOOL)animated
{
    [super viewWillAppear:animated];

    // 恢復執行 requests
    [self.requestQueue setSuspended:NO];
}

Asynchronous Request(非同步請求)

基本上你應該不會想在 mobile 上使用同步請求,因為它會整個拖住畫面的渲染,也不能響應用戶的操作,所以通常的用法是:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
- (void)followMember
{
    NSURL *url = [NSURL URLWithString:@"http://example.com/member/follow"];

    /*
     帶 POST / GET query 參數的請求要用 ASIFormDataRequest
     下載圖片之類的單純的請求就用 ASIHTTPRequest
     */
    ASIFormDataRequest *request = [ASIFormDataRequest requestWithURL:url];

    /*
     通常會把 delegate 指定為當前的 view controller
     你把 callback selector 寫在哪裡,delegate 就是哪個
     */
    [request setDelegate:self];
    [request setDidFinishSelector:@selector(didFollowMember:)];
    [request setDidFailSelector:@selector(didServerFail:)];

    // POST Query
    [request setPostValue:@"1234" forKey:@"user_id"];
    [request setPostValue:@"5678" forKey:@"target_id"];
    [request setPostValue:@"member" forKey:@"follow_type"];

    // 放進 queue 的 request 就是非同步,不需要再特地 [request startAsynchronous] 了
    [requestQueue addOperation:request];
}

- (void)didFollowMember:(ASIHTTPRequest *)request
{
    NSLog("request 得到 HTTP 200 的 response 之後,就會執行這個 callback");
}

- (void)didServerFail:(ASIHTTPRequest *)request
{
    NSLog("server 掛掉、request timeout 或 request 被強制 cancel 掉之後,就會執行這個 callback");
}

callback selector 一定會在 main thread 執行,在 iOS 中,如果要進行 UI 操作(例如 [self.tableView reloadData] 之類的),必須是在 main thread。

延伸閱讀:

Download Image

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
- (void)downloadImage:(NSMutableDictionary *)photoInfo
{
    NSURL *photoURL = [NSURL URLWithString:@"http://example.com/images/1234.jpg"];
    ASIHTTPRequest *request = [ASIHTTPRequest requestWithURL:photoURL];

    [request setDelegate:self];

    // cache
    [request setDownloadCache:[ASIDownloadCache sharedCache]];
    [request setCachePolicy:ASIOnlyLoadIfNotCachedCachePolicy];
    [request setCacheStoragePolicy:ASICachePermanentlyCacheStoragePolicy];
    // [request setSecondsToCache:60 * 60 * 24 * 30]; // cache 30 天

    // time out 自動重試的次數
    [request setNumberOfTimesToRetryOnTimeout:2];

    // callbacks
    [request setDidFinishSelector:@selector(didDownloadImage:)];
    [request setDidFailSelector:@selector(didServerFail:)];
    [request setDidReceiveResponseHeadersSelector:@selector(dummySelector)];
    [request setDidStartSelector:@selector(dummySelector:)];

    /*
     userInfo 的資料會被帶去 callback methods
     而且 request.userInfo 會 retain 它
     
     在這個例子中
     一個頁面可能有很多個 UIImageView
     你可以把對應的 UIImageView 放進 userInfo
     這樣 callback 才知道要把下載下來的圖片放到哪一個 UIImageView
     */
    request.userInfo = photoInfo;

    [self.requestQueue addOperation:request];
}

- (void)didDownloadImage:(ASIHTTPRequest *)request
{
    NSData *imageData = [request responseData];
    UIImage *image = [[UIImage alloc] initWithData:imageData];

    UIImageView *imageView = [request.userInfo objectForKey:@"imageView"];

    if (imageView.subviews.count > 0) {
        [imageView.subviews makeObjectsPerformSelector:@selector(removeFromSuperview)];
    }

    [imageView setImage:image];
    [image release];
}

/*
 我發現如果沒有指定 setDidReceiveResponseHeadersSelector 和 setDidStartSelector
 常常就會發生不明的 crash
 所以我就不求甚解地加了這一行
 
 但是老實說我完全不知道為什麼
 不過事情都搞到這個地步了
 其實我也不是那麼想知道原因
 我只想準時下班啊~~~
 */
- (void)dummySelector:(ASIHTTPRequest *)request
{
    // do nothing
}

延伸閱讀:

Release

在你的 view controller 的 dealloc 這樣寫:

1
2
3
4
5
6
7
8
9
10
11
- (void)dealloc
{
    for (ASIHTTPRequest *request in requestQueue.operations) {
        /*
         因為 ASIHTTPRequest 並不會 retain 它的 delegate
         這樣可以避免 delegate 被 release 之後
         request callback 回來卻找不到東西執行而 crash
        */
        [request clearDelegatesAndCancel];
    }
}

因為 request 被 cancel 之後,會執行 didFailSelector 這個 callback,所以你應該設置 [request setDelegate:nil],這樣就不會執行 callback 了。而 [request clearDelegatesAndCancel] 其實就是 [request setDelegate:nil]; [request cancel];。

原文出自:http://gibuloto.com/blog/asihttprequest/

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值