AFNetworking源碼探究(十二) —— 數(shù)據(jù)解析之子類中協(xié)議方法的實(shí)現(xiàn)(三)

版本記錄

版本號(hào) 時(shí)間
V1.0 2018.03.01

前言

我們做APP發(fā)起網(wǎng)絡(luò)請(qǐng)求,都離不開(kāi)一個(gè)非常有用的框架AFNetworking钦铺,可以說(shuō)這個(gè)框架的知名度已經(jīng)超過(guò)了蘋果的底層網(wǎng)絡(luò)請(qǐng)求部分,很多人可能不知道蘋果底層是如何發(fā)起網(wǎng)絡(luò)請(qǐng)求的,但是一定知道AFNetworking,接下來(lái)幾篇我們就一起詳細(xì)的解析一下這個(gè)框架误褪。感興趣的可以看上面寫的幾篇。
1. AFNetworking源碼探究(一) —— 基本介紹
2. AFNetworking源碼探究(二) —— GET請(qǐng)求實(shí)現(xiàn)之NSURLSessionDataTask實(shí)例化(一)
3. AFNetworking源碼探究(三) —— GET請(qǐng)求實(shí)現(xiàn)之任務(wù)進(jìn)度設(shè)置和通知監(jiān)聽(tīng)(一)
4. AFNetworking源碼探究(四) —— GET請(qǐng)求實(shí)現(xiàn)之代理轉(zhuǎn)發(fā)思想(一)
5. AFNetworking源碼探究(五) —— AFURLSessionManager中NSURLSessionDelegate詳細(xì)解析(一)
6. AFNetworking源碼探究(六) —— AFURLSessionManager中NSURLSessionTaskDelegate詳細(xì)解析(一)
7. AFNetworking源碼探究(七) —— AFURLSessionManager中NSURLSessionDataDelegate詳細(xì)解析(一)
8. AFNetworking源碼探究(八) —— AFURLSessionManager中NSURLSessionDownloadDelegate詳細(xì)解析(一)
9. AFNetworking源碼探究(九) —— AFURLSessionManagerTaskDelegate中三個(gè)轉(zhuǎn)發(fā)代理方法詳細(xì)解析(一)
10. AFNetworking源碼探究(十) —— 數(shù)據(jù)解析之?dāng)?shù)據(jù)解析架構(gòu)的分析(一)
11. AFNetworking源碼探究(十一) —— 數(shù)據(jù)解析之子類中協(xié)議方法的實(shí)現(xiàn)(二)

回顧

上一篇講述了一個(gè)AFURLResponseSerialization協(xié)議以及AFHTTPResponseSerializerAFJSONResponseSerializer類中父類那個(gè)協(xié)議方法的實(shí)現(xiàn)碾褂。這一篇看一下剩下的那四個(gè)子類中該協(xié)議的實(shí)現(xiàn)兽间。


AFXMLParserResponseSerializer

我們看一下協(xié)議的實(shí)現(xiàn)

- (id)responseObjectForResponse:(NSHTTPURLResponse *)response
                           data:(NSData *)data
                          error:(NSError *__autoreleasing *)error
{
    if (![self validateResponse:(NSHTTPURLResponse *)response data:data error:error]) {
        if (!error || AFErrorOrUnderlyingErrorHasCodeInDomain(*error, NSURLErrorCannotDecodeContentData, AFURLResponseSerializationErrorDomain)) {
            return nil;
        }
    }

    return [[NSXMLParser alloc] initWithData:data];
}

這個(gè)很簡(jiǎn)單了吧,首先驗(yàn)證有效性正塌,無(wú)效的話返回nil嘀略,有效的話利用下面的方法返回對(duì)象。

[[NSXMLParser alloc] initWithData:data];

AFXMLDocumentResponseSerializer

我們看一下協(xié)議的實(shí)現(xiàn)

- (id)responseObjectForResponse:(NSURLResponse *)response
                           data:(NSData *)data
                          error:(NSError *__autoreleasing *)error
{
    if (![self validateResponse:(NSHTTPURLResponse *)response data:data error:error]) {
        if (!error || AFErrorOrUnderlyingErrorHasCodeInDomain(*error, NSURLErrorCannotDecodeContentData, AFURLResponseSerializationErrorDomain)) {
            return nil;
        }
    }

    NSError *serializationError = nil;
    NSXMLDocument *document = [[NSXMLDocument alloc] initWithData:data options:self.options error:&serializationError];

    if (error) {
        *error = AFErrorWithUnderlyingError(serializationError, *error);
    }

    return document;
}

下面我們就看一下實(shí)現(xiàn)過(guò)程:

  • 首先判斷是否有效乓诽,無(wú)效的話屎鳍,return nil
  • 如果有效那么就用下面方法進(jìn)行實(shí)例化對(duì)象
NSXMLDocument *document = [[NSXMLDocument alloc] initWithData:data options:self.options error:&serializationError];
  • 如果有錯(cuò)誤,調(diào)用方法合成error對(duì)象

AFPropertyListResponseSerializer

我們看一下協(xié)議的實(shí)現(xiàn)

- (id)responseObjectForResponse:(NSURLResponse *)response
                           data:(NSData *)data
                          error:(NSError *__autoreleasing *)error
{
    if (![self validateResponse:(NSHTTPURLResponse *)response data:data error:error]) {
        if (!error || AFErrorOrUnderlyingErrorHasCodeInDomain(*error, NSURLErrorCannotDecodeContentData, AFURLResponseSerializationErrorDomain)) {
            return nil;
        }
    }

    id responseObject;
    NSError *serializationError = nil;

    if (data) {
        responseObject = [NSPropertyListSerialization propertyListWithData:data options:self.readOptions format:NULL error:&serializationError];
    }

    if (error) {
        *error = AFErrorWithUnderlyingError(serializationError, *error);
    }

    return responseObject;
}

這個(gè)的實(shí)現(xiàn)過(guò)程和上面的是類似的问裕,唯一不同的就是驗(yàn)證有效逮壁,實(shí)例化調(diào)用的方法不一樣,這里是

responseObject = [NSPropertyListSerialization propertyListWithData:data options:self.readOptions format:NULL error:&serializationError];

AFImageResponseSerializer

我們看一下協(xié)議的實(shí)現(xiàn)

- (id)responseObjectForResponse:(NSURLResponse *)response
                           data:(NSData *)data
                          error:(NSError *__autoreleasing *)error
{
    if (![self validateResponse:(NSHTTPURLResponse *)response data:data error:error]) {
        if (!error || AFErrorOrUnderlyingErrorHasCodeInDomain(*error, NSURLErrorCannotDecodeContentData, AFURLResponseSerializationErrorDomain)) {
            return nil;
        }
    }

#if TARGET_OS_IOS || TARGET_OS_TV || TARGET_OS_WATCH
    if (self.automaticallyInflatesResponseImage) {
        return AFInflatedImageFromResponseWithDataAtScale((NSHTTPURLResponse *)response, data, self.imageScale);
    } else {
        return AFImageWithDataAtScale(data, self.imageScale);
    }
#else
    // Ensure that the image is set to it's correct pixel width and height
    NSBitmapImageRep *bitimage = [[NSBitmapImageRep alloc] initWithData:data];
    NSImage *image = [[NSImage alloc] initWithSize:NSMakeSize([bitimage pixelsWide], [bitimage pixelsHigh])];
    [image addRepresentation:bitimage];

    return image;
#endif

    return nil;
}

這里我們可以看到:

  • 首先進(jìn)行的是有效性的驗(yàn)證粮宛,無(wú)效的話返回nil窥淆。
  • 然后利用屬性automaticallyInflatesResponseImage進(jìn)行判斷邏輯的執(zhí)行。
/**
 Whether to automatically inflate response image data for compressed formats (such as PNG or JPEG). Enabling this can significantly improve drawing performance on iOS when used with `setCompletionBlockWithSuccess:failure:`, as it allows a bitmap representation to be constructed in the background rather than on the main thread. `YES` by default.
 */
@property (nonatomic, assign) BOOL automaticallyInflatesResponseImage;

是否自動(dòng)為壓縮格式(如PNG或JPEG)膨脹響應(yīng)圖像數(shù)據(jù)巍杈。 如果與setCompletionBlockWithSuccess:failure:一起使用忧饭,啟用它可以顯著提高iOS上的繪圖性能,因?yàn)樗试S在后臺(tái)而不是在主線程中構(gòu)建位圖表示筷畦。 默認(rèn)為YES词裤。

如果可以膨脹,調(diào)用下面函數(shù)鳖宾,返回UIImage對(duì)象并return吼砂。

static UIImage * AFInflatedImageFromResponseWithDataAtScale(NSHTTPURLResponse *response, NSData *data, CGFloat scale) {
    if (!data || [data length] == 0) {
        return nil;
    }

    CGImageRef imageRef = NULL;
    CGDataProviderRef dataProvider = CGDataProviderCreateWithCFData((__bridge CFDataRef)data);

    if ([response.MIMEType isEqualToString:@"image/png"]) {
        imageRef = CGImageCreateWithPNGDataProvider(dataProvider,  NULL, true, kCGRenderingIntentDefault);
    } else if ([response.MIMEType isEqualToString:@"image/jpeg"]) {
        imageRef = CGImageCreateWithJPEGDataProvider(dataProvider, NULL, true, kCGRenderingIntentDefault);

        if (imageRef) {
            CGColorSpaceRef imageColorSpace = CGImageGetColorSpace(imageRef);
            CGColorSpaceModel imageColorSpaceModel = CGColorSpaceGetModel(imageColorSpace);

            // CGImageCreateWithJPEGDataProvider does not properly handle CMKY, so fall back to AFImageWithDataAtScale
            if (imageColorSpaceModel == kCGColorSpaceModelCMYK) {
                CGImageRelease(imageRef);
                imageRef = NULL;
            }
        }
    }

    CGDataProviderRelease(dataProvider);

    UIImage *image = AFImageWithDataAtScale(data, scale);
    if (!imageRef) {
        if (image.images || !image) {
            return image;
        }

        imageRef = CGImageCreateCopy([image CGImage]);
        if (!imageRef) {
            return nil;
        }
    }

    size_t width = CGImageGetWidth(imageRef);
    size_t height = CGImageGetHeight(imageRef);
    size_t bitsPerComponent = CGImageGetBitsPerComponent(imageRef);

    if (width * height > 1024 * 1024 || bitsPerComponent > 8) {
        CGImageRelease(imageRef);

        return image;
    }

    // CGImageGetBytesPerRow() calculates incorrectly in iOS 5.0, so defer to CGBitmapContextCreate
    size_t bytesPerRow = 0;
    CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
    CGColorSpaceModel colorSpaceModel = CGColorSpaceGetModel(colorSpace);
    CGBitmapInfo bitmapInfo = CGImageGetBitmapInfo(imageRef);

    if (colorSpaceModel == kCGColorSpaceModelRGB) {
        uint32_t alpha = (bitmapInfo & kCGBitmapAlphaInfoMask);
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wassign-enum"
        if (alpha == kCGImageAlphaNone) {
            bitmapInfo &= ~kCGBitmapAlphaInfoMask;
            bitmapInfo |= kCGImageAlphaNoneSkipFirst;
        } else if (!(alpha == kCGImageAlphaNoneSkipFirst || alpha == kCGImageAlphaNoneSkipLast)) {
            bitmapInfo &= ~kCGBitmapAlphaInfoMask;
            bitmapInfo |= kCGImageAlphaPremultipliedFirst;
        }
#pragma clang diagnostic pop
    }

    CGContextRef context = CGBitmapContextCreate(NULL, width, height, bitsPerComponent, bytesPerRow, colorSpace, bitmapInfo);

    CGColorSpaceRelease(colorSpace);

    if (!context) {
        CGImageRelease(imageRef);

        return image;
    }

    CGContextDrawImage(context, CGRectMake(0.0f, 0.0f, width, height), imageRef);
    CGImageRef inflatedImageRef = CGBitmapContextCreateImage(context);

    CGContextRelease(context);

    UIImage *inflatedImage = [[UIImage alloc] initWithCGImage:inflatedImageRef scale:scale orientation:image.imageOrientation];

    CGImageRelease(inflatedImageRef);
    CGImageRelease(imageRef);

    return inflatedImage;
}
#endif

如果不可以膨脹,那么調(diào)用下面的函數(shù)返回UIImage對(duì)象鼎文。

static UIImage * AFImageWithDataAtScale(NSData *data, CGFloat scale) {
    UIImage *image = [UIImage af_safeImageWithData:data];
    if (image.images) {
        return image;
    }
    
    return [[UIImage alloc] initWithCGImage:[image CGImage] scale:scale orientation:image.imageOrientation];
}

AFCompoundResponseSerializer

下面看一下協(xié)議在該類中的實(shí)現(xiàn)

- (id)responseObjectForResponse:(NSURLResponse *)response
                           data:(NSData *)data
                          error:(NSError *__autoreleasing *)error
{
    for (id <AFURLResponseSerialization> serializer in self.responseSerializers) {
        if (![serializer isKindOfClass:[AFHTTPResponseSerializer class]]) {
            continue;
        }

        NSError *serializerError = nil;
        id responseObject = [serializer responseObjectForResponse:response data:data error:&serializerError];
        if (responseObject) {
            if (error) {
                *error = AFErrorWithUnderlyingError(serializerError, *error);
            }

            return responseObject;
        }
    }

    return [super responseObjectForResponse:response data:data error:error];
}

這里要遍歷數(shù)組

/**
 The component response serializers.
 */
@property (readonly, nonatomic, copy) NSArray <id<AFURLResponseSerialization>> *responseSerializers;

這個(gè)數(shù)組中的元素都是遵守AFURLResponseSerialization協(xié)議的渔肩。然后進(jìn)行判斷如果類型不是AFHTTPResponseSerializer,那么就continue跳出本次循環(huán)拇惋,繼續(xù)進(jìn)行下次的遍歷周偎。

如果類型是AFHTTPResponseSerializer,就利用下面方法進(jìn)行實(shí)例化并返回撑帖。

id responseObject = [serializer responseObjectForResponse:response data:data error:&serializerError];

后記

本篇主要講述剩下的五個(gè)子類中協(xié)議方法的實(shí)現(xiàn)蓉坎。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市胡嘿,隨后出現(xiàn)的幾起案子蛉艾,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 216,402評(píng)論 6 499
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件伺通,死亡現(xiàn)場(chǎng)離奇詭異箍土,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)罐监,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,377評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門吴藻,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人弓柱,你說(shuō)我怎么就攤上這事沟堡。” “怎么了矢空?”我有些...
    開(kāi)封第一講書(shū)人閱讀 162,483評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵航罗,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我屁药,道長(zhǎng)粥血,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,165評(píng)論 1 292
  • 正文 為了忘掉前任酿箭,我火速辦了婚禮复亏,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘缭嫡。我一直安慰自己缔御,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,176評(píng)論 6 388
  • 文/花漫 我一把揭開(kāi)白布妇蛀。 她就那樣靜靜地躺著耕突,像睡著了一般。 火紅的嫁衣襯著肌膚如雪评架。 梳的紋絲不亂的頭發(fā)上眷茁,一...
    開(kāi)封第一講書(shū)人閱讀 51,146評(píng)論 1 297
  • 那天,我揣著相機(jī)與錄音古程,去河邊找鬼蔼卡。 笑死,一個(gè)胖子當(dāng)著我的面吹牛挣磨,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播荤懂,決...
    沈念sama閱讀 40,032評(píng)論 3 417
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼茁裙,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了节仿?” 一聲冷哼從身側(cè)響起晤锥,我...
    開(kāi)封第一講書(shū)人閱讀 38,896評(píng)論 0 274
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后矾瘾,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體女轿,經(jīng)...
    沈念sama閱讀 45,311評(píng)論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,536評(píng)論 2 332
  • 正文 我和宋清朗相戀三年壕翩,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了蛉迹。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,696評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡放妈,死狀恐怖北救,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情芜抒,我是刑警寧澤珍策,帶...
    沈念sama閱讀 35,413評(píng)論 5 343
  • 正文 年R本政府宣布,位于F島的核電站宅倒,受9級(jí)特大地震影響攘宙,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜拐迁,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,008評(píng)論 3 325
  • 文/蒙蒙 一蹭劈、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧唠亚,春花似錦链方、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,659評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至割卖,卻和暖如春前酿,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背鹏溯。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,815評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工罢维, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人丙挽。 一個(gè)月前我還...
    沈念sama閱讀 47,698評(píng)論 2 368
  • 正文 我出身青樓肺孵,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親颜阐。 傳聞我的和親對(duì)象是個(gè)殘疾皇子平窘,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,592評(píng)論 2 353

推薦閱讀更多精彩內(nèi)容