CFNetwork 的使用

1、CFNetwork

  • CFNetwork 是基于 OS 层 BSDSocket 封装(纯 C),用于网络通信,早期的网络请求框架 ASIHTTPRequest 就是基于 CFNetwork 进行的封装。

  • 主要使用的 API:CFSocket 用于底层的通信,CFStream 用于数据的读写。

2、基本使用

2.1 下载图片

  • 下载图片

    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
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    #import <CFNetwork/CFNetwork.h>

    @interface ViewController ()

    @property (weak, nonatomic) IBOutlet UIImageView *imageV;

    @property (nonatomic, strong) NSMutableData *imageData;

    @end

    @implementation ViewController

    - (IBAction)requestImage:(id)sender {

    [UIApplication sharedApplication].networkActivityIndicatorVisible = YES;

    [NSThread detachNewThreadSelector:@selector(startRequest) toTarget:self withObject:nil];
    }

    - (void)startRequest {

    // url
    CFStringRef urlStr = CFSTR("http://pics.sc.chinaz.com/files/pic/pic9/201605/apic20649.jpg");

    // GET 请求
    CFStringRef method = CFSTR("GET");

    // 构造 url
    CFURLRef url = CFURLCreateWithString(kCFAllocatorDefault, urlStr, NULL);

    // http 请求
    CFHTTPMessageRef request = CFHTTPMessageCreateRequest(kCFAllocatorDefault, method, url, kCFHTTPVersion1_1);
    CFRelease(url);

    // 创建一个读取流,读取网络数据
    CFReadStreamRef readStream = CFReadStreamCreateForHTTPRequest(kCFAllocatorDefault, request);
    CFRelease(request);

    // 设置流的 context,这里将 self 传入,用于回调
    CFStreamClientContext ctx = {0, (__bridge void *)(self), NULL, NULL, NULL};

    // 设置回调事件,用于监听网络事件
    // kCFStreamEventNone,(没有事件发生)
    // kCFStreamEventOpenCompleted,(流被成功打开)
    // kCFStreamEventHasBytesAvailable,(有数据可以读取)
    // kCFStreamEventCanAcceptBytes,(流可以接受写入数据(用于写入流))
    // kCFStreamEventErrorOccurred,(在流上有错误发生)
    // kCFStreamEventEndEncountered ,(到达了流的结束位置)
    CFOptionFlags event = kCFStreamEventHasBytesAvailable | kCFStreamEventEndEncountered;

    CFReadStreamSetClient(readStream, event, myCallBack, &ctx);

    // 打开输入流
    CFReadStreamOpen(readStream);

    // 将流加入到 runloop 中
    CFReadStreamScheduleWithRunLoop(readStream, CFRunLoopGetCurrent(), kCFRunLoopCommonModes);

    // 开启 runloop
    CFRunLoopRun();
    }

    // 回调函数
    void myCallBack(CFReadStreamRef stream, CFStreamEventType type, void *clientCallBackInfo) {

    ViewController *selfClass = (__bridge ViewController *)clientCallBackInfo;

    if (type == kCFStreamEventHasBytesAvailable) {

    UInt8 buff[255];
    CFIndex length = CFReadStreamRead(stream, buff, 255);

    if (!selfClass.imageData) {
    selfClass.imageData = [NSMutableData data];
    }
    [selfClass.imageData appendBytes:buff length:length];
    }

    if (type == kCFStreamEventEndEncountered) {

    [UIApplication sharedApplication].networkActivityIndicatorVisible = NO;

    [selfClass requestImageComplete];

    // 关闭流
    CFReadStreamClose(stream);

    // 将流从 runloop 中移除
    CFReadStreamUnscheduleFromRunLoop(stream, CFRunLoopGetCurrent(), kCFRunLoopCommonModes);
    }
    }

    - (void)requestImageComplete {

    UIImage *image = [UIImage imageWithData:self.imageData];
    self.imageV.image = image;
    }

    @end

文章目录
  1. 1. 1、CFNetwork
  2. 2. 2、基本使用
    1. 2.1. 2.1 下载图片
隐藏目录