Cocoa学习

我的Cocoa/Cocoa Touch学习笔记

用NSMutableURLRequest发送图片

DragFan目前的网络连接使用了ASIHTTPRequest这个第三方库。ASIHTTPRequest是一个相对非常庞大的库,在心理上我总觉得用在DragFan里有点大材小用了。因此,我今天试着寻找了一下替代方案。很幸运,我找到了一个不错的替代方案,而且是利用现有的Cocoa API,而且在iOS下也是能使用的。

尽管印象中看到过文章说用Cocoa的网络API的性能没有用CoreFoundation的性能好,但是目前我在写的程序并没有特别的需要高性能,而且用Cocoa的API,程序的可读性和内存管理也更加直观,应该说,是一个比较好的方案。

废话了一通,下面来看看究竟是如何实现的:

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
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
#define FANFOU_SEND_PHOTO_API @"http://api.fanfou.com/photos/upload.json"

- (IBAction)sendMessage:(id)sender {
    // 创建Request对象
    NSMutableURLRequest *req = [[NSMutableURLRequest alloc] initWithURL:[NSURL URLWithString:FANFOU_SEND_PHOTO_API]
                                                            cachePolicy:NSURLRequestUseProtocolCachePolicy
                                                        timeoutInterval:60.0];
    // 定义boundary
    NSString *boundary = @"----Boundary+WhateverYouLikeToPutInHere----datatata--done";
    // 使用POST方法
    [req setHTTPMethod:@"POST"];
    // 设置Content-Type
    [req setValue:[NSString stringWithFormat:@"multipart/form-data; boundary=%@", boundary, nil] forHTTPHeaderField:@"Content-Type"];

    // 把图片变成data。
    NSImage *theImage = [self.imageView image];
    NSBitmapImageRep *bitmap = [[theImage representations] objectAtIndex:0];
    NSData *imageData = [bitmap representationUsingType:NSJPEGFileType properties: nil];

    // 需要POST的键值对
    NSDictionary *values = [NSDictionary dictionaryWithObjectsAndKeys:[messageField string], @"status", imageData, @"photo", nil];

    // 初始化POST Data
    NSMutableData *d = [NSMutableData data];

    // 遍历键值对,将其转换成NSData
    for (NSString *key in [values allKeys]) {

        // Append一个Boundary
        [d appendData:[[NSString stringWithFormat:@"\r\n--%@\r\n", boundary] dataUsingEncoding:NSUTF8StringEncoding]];

        id currentValue = [values objectForKey:key];

        if( [currentValue isKindOfClass:[NSData class]] && [NSImageRep imageRepClassForData:currentValue] != nil ) {
            // 如果是图片对象的处理方法。
            // 设置Content-Disposition,这里设置图片对应的key的名字
            [d appendData:[[NSString stringWithFormat:@"Content-Disposition: form-data; name=\"%@\"; filename=\"image.png\"\r\n", key]
                           dataUsingEncoding:NSUTF8StringEncoding]];
            // 设置图片的Content-Type
            [d appendData:[@"Content-Type: image/png\r\n" dataUsingEncoding:NSASCIIStringEncoding]];
            // 设置传输编码为二进制
            [d appendData:[@"Content-Transfer-Encoding: binary\r\n\r\n" dataUsingEncoding:NSASCIIStringEncoding]];
            // Append图片
            [d appendData:currentValue];
        }
        else {
            // 字符串值的处理方法
            // Append一个Boundary
            [d appendData:[[NSString stringWithFormat:@"\r\n--%@\r\n", boundary] dataUsingEncoding:NSUTF8StringEncoding]];
            // 设置字符串键
            [d appendData:[@"Content-Disposition: form-data; name=\"status\"\r\n\r\n" dataUsingEncoding:NSUTF8StringEncoding]];
            // 设置字符串值
            [d appendData:[[NSString stringWithFormat:@"%@", currentValue] dataUsingEncoding:NSUTF8StringEncoding]];
        }
    }
    // 最后Append一个Boundary
    [d appendData:[[NSString stringWithFormat:@"\r\n--%@--\r\n", boundary] dataUsingEncoding:NSUTF8StringEncoding]];
    // 设置数据为请求的Body
    [req setHTTPBody:d];

    // 建立一个连接,用来发送请求,并且设置delegate为self,这里主要用来处理BasicAuth
    NSURLConnection *theConnection=[[NSURLConnection alloc] initWithRequest:req delegate:self];
    if (theConnection) {
        // 处理连接成功
    } else {
        // 处理链接失败
    }
    [req release];
}

// NSURLConnection的Delegate方法,用来处理Basic Auth。
 -(void)connection:(NSURLConnection *)connection didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge
{
    if ([challenge previousFailureCount] == 0) {
        NSURLCredential *newCredential;
        newCredential = [NSURLCredential credentialWithUser:@"YOUR_USER_NAME"
                                                   password:@"YOUR_PASSWORD"
                                                persistence:NSURLCredentialPersistenceNone];
        [[challenge sender] useCredential:newCredential
               forAuthenticationChallenge:challenge];
    } else {
        [[challenge sender] cancelAuthenticationChallenge:challenge];
        // 处理认证失败
    }
}

利用NSMutableURLRequest应该也能够轻松的实现饭否Basic Auth API的Cocoa封装,配合其他的一些库,要实现OAuth的封装应该也没有什么问题的。我目前对NSMutableURLRequest的理解还只是一知半解,所以继续研究文档去。。。下一版DragFan中,我会用NSMutableURLRequest替代ASIHTTPRequest,实现DragFan的图片发送功能。

(本文参考了这里这里

(全文完)

Comments