- (SDWebImageCombinedOperation *)loadImageWithURL:(nullableNSURL *)url options:(SDWebImageOptions)options context:(nullable SDWebImageContext *)context progress:(nullable SDImageLoaderProgressBlock)progressBlock completed:(nonnull SDInternalCompletionBlock)completedBlock { // Invoking this method without a completedBlock is pointless NSAssert(completedBlock != nil, @"If you mean to prefetch the image, use -[SDWebImagePrefetcher prefetchURLs] instead"); //如果传入的URL是字符串则将其转换为NSURL if ([url isKindOfClass:NSString.class]) { url = [NSURL URLWithString:(NSString *)url]; }
// 如果不是NSURL则设置url为空,避免崩溃 if (![url isKindOfClass:NSURL.class]) { url = nil; }
+ (void)initialize { if (NSClassFromString(@"SDNetworkActivityIndicator")) {
#pragma clang diagnostic push #pragma clang diagnostic ignored "-Warc-performSelector-leaks" id activityIndicator = [NSClassFromString(@"SDNetworkActivityIndicator") performSelector:NSSelectorFromString(@"sharedActivityIndicator")]; #pragma clang diagnostic pop
// Remove observer in case it was previously added. [[NSNotificationCenter defaultCenter] removeObserver:activityIndicator name:SDWebImageDownloadStartNotification object:nil]; [[NSNotificationCenter defaultCenter] removeObserver:activityIndicator name:SDWebImageDownloadStopNotification object:nil];
// Identify the operation that runs this task and pass it the delegate method NSOperation<SDWebImageDownloaderOperation> *dataOperation = [self operationWithTask:dataTask]; if ([dataOperation respondsToSelector:@selector(URLSession:dataTask:didReceiveData:)]) { [dataOperation URLSession:session dataTask:dataTask didReceiveData:data]; } }
//....... //获取缓存key UIImage *image; id<SDWebImageCacheKeyFilter> cacheKeyFilter = context[SDWebImageContextCacheKeyFilter]; NSString *cacheKey; if (cacheKeyFilter) { cacheKey = [cacheKeyFiltercacheKeyForURL:imageURL]; } else { cacheKey = imageURL.absoluteString; } //获取scale BOOL decodeFirstFrame = SD_OPTIONS_CONTAINS(options, SDWebImageDecodeFirstFrameOnly); NSNumber *scaleValue = context[SDWebImageContextImageScaleFactor]; CGFloat scale = scaleValue.doubleValue >= 1 ? scaleValue.doubleValue : SDImageScaleFactorForKey(cacheKey); //构建解码Option SDImageCoderOptions *coderOptions = @{SDImageCoderDecodeFirstFrameOnly : @(decodeFirstFrame), SDImageCoderDecodeScaleFactor : @(scale)}; if (context) { SDImageCoderMutableOptions *mutableCoderOptions = [coderOptionsmutableCopy]; [mutableCoderOptionssetValue:contextforKey:SDImageCoderWebImageContext]; coderOptions = [mutableCoderOptionscopy]; } //获取对应的渐进式解码器 id<SDProgressiveImageCoder> progressiveCoder = objc_getAssociatedObject(operation, SDImageLoaderProgressiveCoderKey); if (!progressiveCoder) { // We need to create a new instance for progressive decoding to avoid conflicts for (id<SDImageCoder>coder in[SDImageCodersManagersharedManager].coders.reverseObjectEnumerator) { if ([coderconformsToProtocol:@protocol(SDProgressiveImageCoder)] && [((id<SDProgressiveImageCoder>)coder) canIncrementalDecodeFromData:imageData]) { //通过Options来创建渐进式解码器 progressiveCoder = [[[coderclass] alloc] initIncrementalWithOptions:coderOptions]; break; } } objc_setAssociatedObject(operation, SDImageLoaderProgressiveCoderKey, progressiveCoder, OBJC_ASSOCIATION_RETAIN_NONATOMIC); } //...... //将图片数据更新到渐进式解码器 [progressiveCoderupdateIncrementalData:imageDatafinished:finished]; //.......... if (!image) { //进行解码 image = [progressiveCoderincrementalDecodedImageWithOptions:coderOptions]; } if (image) { //是否需要解码 BOOL shouldDecode = !SD_OPTIONS_CONTAINS(options, SDWebImageAvoidDecodeImage); if ([image.classconformsToProtocol:@protocol(SDAnimatedImage)]) { // `SDAnimatedImage` do not decode shouldDecode = NO; } elseif (image.sd_isAnimated) { // animated image do not decode shouldDecode = NO; } //如果需要解码则调用decodedImageWithImage进行解码 if (shouldDecode) { image = [SDImageCoderHelperdecodedImageWithImage:image]; } image.sd_isIncremental = YES; } return image; }
上面最关键的部分在于:
[progressiveCoder updateIncrementalData:imageData finished:finished]; image = [progressiveCoder incrementalDecodedImageWithOptions:coderOptions]; if (image) { //是否需要解码 BOOL shouldDecode = !SD_OPTIONS_CONTAINS(options, SDWebImageAvoidDecodeImage); if ([image.class conformsToProtocol:@protocol(SDAnimatedImage)]) { // `SDAnimatedImage` do not decode shouldDecode = NO; } elseif (image.sd_isAnimated) { // animated image do not decode shouldDecode = NO; } //如果需要解码则调用decodedImageWithImage进行解码 if (shouldDecode) { image = [SDImageCoderHelper decodedImageWithImage:image]; } // mark the image as progressive (completionBlock one are not mark as progressive) image.sd_isIncremental = YES; }
#pragma mark - Request and Response Information ///============================================================================= /// @name Request and Response Information ///=============================================================================
NSString *downloadTargetPath; BOOL isDirectory; if(![[NSFileManager defaultManager] fileExistsAtPath:downloadPath isDirectory:&isDirectory]) { isDirectory = NO; } // If targetPath is a directory, use the file name we got from the urlRequest. // Make sure downloadTargetPath is always a file, not directory. // 构建下载路径downloadTargetPath if (isDirectory) { //如果给定的downloadpath是目录路径,那么将会将下载url下的最后部分作为文件名添加到最后,形成最终的下载文件地址 NSString *fileName = [urlRequest.URL lastPathComponent]; downloadTargetPath = [NSString pathWithComponents:@[downloadPath, fileName]]; } else { downloadTargetPath = downloadPath; } // 在下载前如果文件存在先直接删除? 直接删除不先下到缓存再? if ([[NSFileManager defaultManager] fileExistsAtPath:downloadTargetPath]) { [[NSFileManager defaultManager] removeItemAtPath:downloadTargetPath error:nil]; }
// When the request is cancelled and removed from records, the underlying // AFNetworking failure callback will still kicks in, resulting in a nil `request`. // // Here we choose to completely ignore cancelled tasks. Neither success or failure // callback will be called. if (!request) { return; }
- (void)lt_addLogger:(id <DDLogger>)logger level:(DDLogLevel)level { // Add to loggers array. // Need to create loggerQueue if loggerNode doesn't provide one.
//判断是否已经存在了 for (DDLoggerNode* node inself._loggers) { if (node->_logger == logger && node->_level == level) { return; } }
NSAssert(dispatch_get_specific(GlobalLoggingQueueIdentityKey), @"This method should only be run on the logging thread/queue");
// Filter cycles that have been broken down since we found them. // These are false-positive that were picked-up and are transient cycles. NSMutableSet<NSArray<FBObjectiveCGraphElement *> *> *brokenCycles = [NSMutableSetset]; for (NSArray<FBObjectiveCGraphElement *> *itemCycle in allRetainCycles) { for (FBObjectiveCGraphElement*element in itemCycle) { if (element.object ==nil) { // At least one element of the cycle has been removed, thus breaking // the cycle. [brokenCycles addObject:itemCycle]; break; } } } [allRetainCycles minusSet:brokenCycles];
// Take next adjecent node to that child. Wrapper object can // persist iteration state. If we see that node again, it will // give us new adjacent node unless it runs out of them //取top节点的next节点,也就是这个object可能持有的对象。 FBNodeEnumerator*firstAdjacent = [top nextObject]; if (firstAdjacent) { //如果存在未访问到的节点 // Current node still has some adjacent not-visited nodes
BOOL shouldPushToStack =NO; // 检查是否已经访问过了 // Check if child was already seen in that path if ([objectsOnPath containsObject:firstAdjacent]) { // We have caught a retain cycle //如果该节点已经存在被访问过的对象中,说明构成了retain cycle // Ignore the first element which is equal to firstAdjacent, use firstAdjacent // we're doing that because firstAdjacent has set all contexts, while its // first occurence could be a root without any context NSUInteger index = [stack indexOfObject:firstAdjacent]; NSInteger length = [stack count] - index;
if (index ==NSNotFound) { // Object got deallocated between checking if it exists and grabbing its index shouldPushToStack =YES; } else { //计算出firstAdj出现的位置,同时计算出路径的长度,将这一系列的节点(object),也就是环,存放在array里面。 //将这个array存放到retainCycles集合中。 NSRange cycleRange =NSMakeRange(index, length); NSMutableArray<FBNodeEnumerator *> *cycle = [[stack subarrayWithRange:cycleRange] mutableCopy]; [cycle replaceObjectAtIndex:0 withObject:firstAdjacent];
// 1. Unwrap the cycle // 2. Shift to lowest address (if we omit that, and the cycle is created by same class, // we might have duplicates) // 3. Shift by class (lexicographically)
[retainCycles addObject:[self _shiftToUnifiedCycle:[self _unwrapCycle:cycle]]]; } } else { // Node is clear to check, add it to stack and continue shouldPushToStack =YES; }
if (shouldPushToStack) { if ([stack count] < stackDepth) { [stack addObject:firstAdjacent]; } } } else { // Node has no more adjacent nodes, it itself is done, move on [stack removeLastObject]; [objectsOnPath removeObject:top]; } } } return retainCycles; }
//将全部的强引用对象封装成FBObjectiveCGraphElement for (id<FBObjectReference> ref in strongIvars) { id referencedObject = [ref objectReferenceFromObject:self.object]; if (referencedObject) { NSArray<NSString *> *namePath = [ref namePath]; FBObjectiveCGraphElement*element =FBWrapObjectGraphElementWithContext(self, referencedObject, self.configuration, namePath); if (element) { [retainedObjects addObject:element]; } } }
if ([NSStringFromClass(aCls) hasPrefix:@"__NSCF"]) { /** If we are dealing with toll-free bridged collections, we are not guaranteed that the collection will hold only Objective-C objects. We are not able to check in runtime what callbacks it uses to retain/release (if any) and we could easily crash here. */ return [NSSet setWithArray:retainedObjects]; }
if (class_isMetaClass(aCls)) { // If it's a meta-class it can conform to following protocols, // but it would crash when trying enumerating returnnil; }
BOOL isKeyValued =NO; if ([aCls instancesRespondToSelector:@selector(objectForKey:)]) { isKeyValued =YES; }
/** This codepath is prone to errors. When you enumerate a collection that can be mutated while enumeration we fall into risk of crash. To save ourselves from that we will catch such exception and try again. We should not try this endlessly, so at some point we will simply give up. */ NSInteger tries =10; for (NSInteger i =0; i < tries; ++i) { // If collection is mutated we want to rollback and try again - let's keep refs in temporary set NSMutableSet*temporaryRetainedObjects = [NSMutableSet new]; @try { for (id subobject inself.object) { if (retainsKeys) { FBObjectiveCGraphElement*element =FBWrapObjectGraphElement(self, subobject, self.configuration); if (element) { [temporaryRetainedObjects addObject:element]; } } if (isKeyValued && retainsValues) { FBObjectiveCGraphElement*element =FBWrapObjectGraphElement(self, [self.object objectForKey:subobject], self.configuration); if (element) { [temporaryRetainedObjects addObject:element]; } } } } @catch (NSException*exception) { // mutation happened, we want to try enumerating again continue; }
// If we are here it means no exception happened and we want to break outer loop [retainedObjects addObjectsFromArray:[temporaryRetainedObjects allObjects]]; break; } }
// Grab a strong reference to the object, otherwise it can crash while doing // nasty stuff on deallocation __attribute__((objc_precise_lifetime)) id anObject = self.object;
for (id object in allRetainedReferences) { FBObjectiveCGraphElement *element = FBWrapObjectGraphElement(self, object, self.configuration); if (element) { [results addObject:element]; } }
/** BLOCK_HAS_CTOR - Block has a C++ constructor/destructor, which gives us a good chance it retains objects that are not pointer aligned, so omit them. !BLOCK_HAS_COPY_DISPOSE - Block doesn't have a dispose function, so it does not retain objects and we are not able to blackbox it. */ if ((blockLiteral->flags & BLOCK_HAS_CTOR) || !(blockLiteral->flags & BLOCK_HAS_COPY_DISPOSE)) { returnnil; }
//计算出需要填充的fake对象数量 // Figure out the number of pointers it takes to fill out the object, rounding up. const size_t elements = (blockLiteral->descriptor->size + ptrSize - 1) / ptrSize;
// 创建fack对象 // Create a fake object of the appropriate length. void *obj[elements]; void *detectors[elements];
for (size_t i = 0; i < elements; ++i) { FBBlockStrongRelationDetector *detector = [FBBlockStrongRelationDetector new]; obj[i] = detectors[i] = detector; } //调用dispose_helper,这时候会调用每个FBBlockStrongRelationDetector的release方法,这时候会将strong设置为YES @autoreleasepool { dispose_helper(obj); } // Run through the release detectors and add each one that got released to the object's // strong ivar layout. NSMutableIndexSet *layout = [NSMutableIndexSet indexSet]; //判断strong是否为YES,如果为YES表示为强引用,则将其添加到layout for (size_t i = 0; i < elements; ++i) { FBBlockStrongRelationDetector *detector = (FBBlockStrongRelationDetector *)(detectors[i]); if (detector.isStrong) { [layout addIndex:i]; } // Destroy detectors [detector trueRelease]; } return layout; }
// VC is not dealloced until disappear when popped using a left-edge swipe gesture externconstvoid *const kHasBeenPoppedKey; objc_setAssociatedObject(poppedViewController, kHasBeenPoppedKey, @(YES), OBJC_ASSOCIATION_RETAIN); return poppedViewController; }
- (void)assertNotDealloc { if ([MLeakedObjectProxy isAnyObjectLeakedAtPtrs:[self parentPtrs]]) { return; } [MLeakedObjectProxy addLeakedObject:self]; NSString*className =NSStringFromClass([selfclass]); NSLog(@"Possibly Memory Leak.\nIn case that %@ should not be dealloced, override -willDealloc in %@ by returning NO.\nView-ViewController stack: %@", className, className, [self viewStack]); }
@interface_YYModelMeta : NSObject{ @package YYClassInfo *_classInfo; //Model类的信息 /// Key:mapped key and key path, Value:_YYModelPropertyMeta. NSDictionary *_mapper; //所有属性的key和keyPath /// Array<_YYModelPropertyMeta>, all property meta of this model. NSArray *_allPropertyMetas; //所有属性的信息 /// Array<_YYModelPropertyMeta>, property meta which is mapped to a key path. NSArray *_keyPathPropertyMetas; //属于keyPath的属性列表 /// Array<_YYModelPropertyMeta>, property meta which is mapped to multi keys. NSArray *_multiKeysPropertyMetas; //一个属性多个key的属性列表 /// The number of mapped key (and key path), same to _mapper.count. NSUInteger _keyMappedCount; //全部属性数量 /// Model class type. YYEncodingNSType _nsType; //Model类的对象 //这个类实现覆盖方法的情况 BOOL _hasCustomWillTransformFromDictionary; BOOL _hasCustomTransformFromDictionary; BOOL _hasCustomTransformToDictionary; BOOL _hasCustomClassFromDictionary; } @end
Apple said: The top level object is an NSArray or NSDictionary. All objects are instances of NSString, NSNumber, NSArray, NSDictionary, or NSNull. All dictionary keys are instances of NSString. Numbers are not NaN or infinity.
staticid ModelToJSONObjectRecursive(NSObject *model) { // 对于简单的NSString,NSNumber,nill类型 if (!model || model == (id)kCFNull) return model; if ([model isKindOfClass:[NSStringclass]]) return model; if ([model isKindOfClass:[NSNumberclass]]) return model; if ([model isKindOfClass:[NSURLclass]]) return ((NSURL *)model).absoluteString; if ([model isKindOfClass:[NSAttributedStringclass]]) return ((NSAttributedString *)model).string; if ([model isKindOfClass:[NSDateclass]]) return [YYISODateFormatter() stringFromDate:(id)model]; if ([model isKindOfClass:[NSDataclass]]) returnnil; //如果当前对象是NSDictionary if ([model isKindOfClass:[NSDictionaryclass]]) { // 简单的字典 if ([NSJSONSerialization isValidJSONObject:model]) return model; // 对象是复杂的对象 NSMutableDictionary *newDic = [NSMutableDictionary new]; [((NSDictionary *)model) enumerateKeysAndObjectsUsingBlock:^(NSString *key, id obj, BOOL *stop) { NSString *stringKey = [key isKindOfClass:[NSStringclass]] ? key : key.description; if (!stringKey) return; //复杂对象需要递归转换 id jsonObj = ModelToJSONObjectRecursive(obj); if (!jsonObj) jsonObj = (id)kCFNull; newDic[stringKey] = jsonObj; }]; return newDic; } //如果当前对象是NSSet if ([model isKindOfClass:[NSSetclass]]) { // 简单的NSSet NSArray *array = ((NSSet *)model).allObjects; if ([NSJSONSerialization isValidJSONObject:array]) return array; // 对象是复杂的对象 NSMutableArray *newArray = [NSMutableArray new]; for (id obj in array) { if ([obj isKindOfClass:[NSStringclass]] || [obj isKindOfClass:[NSNumberclass]]) { [newArray addObject:obj]; } else { id jsonObj = ModelToJSONObjectRecursive(obj); if (jsonObj && jsonObj != (id)kCFNull) [newArray addObject:jsonObj]; } } return newArray; } //如果当前对象是NSArray if ([model isKindOfClass:[NSArrayclass]]) { // 简单的NSArray if ([NSJSONSerialization isValidJSONObject:model]) return model; // 对象是复杂的对象 NSMutableArray *newArray = [NSMutableArray new]; for (id obj in (NSArray *)model) { if ([obj isKindOfClass:[NSStringclass]] || [obj isKindOfClass:[NSNumberclass]]) { [newArray addObject:obj]; } else { id jsonObj = ModelToJSONObjectRecursive(obj); if (jsonObj && jsonObj != (id)kCFNull) [newArray addObject:jsonObj]; } } return newArray; } //获取Model信息 _YYModelMeta *modelMeta = [_YYModelMeta metaWithClass:[model class]]; if (!modelMeta || modelMeta->_keyMappedCount == 0) returnnil; NSMutableDictionary *result = [[NSMutableDictionary alloc] initWithCapacity:64]; __unsafe_unretainedNSMutableDictionary *dic = result; // avoid retain and release in block [modelMeta->_mapper enumerateKeysAndObjectsUsingBlock:^(NSString *propertyMappedKey, _YYModelPropertyMeta *propertyMeta, BOOL *stop) { if (!propertyMeta->_getter) return; // 通过属性信息中的_getter方法使用objc_msgSend从model中获取当前对应属性的值,值获取到了,mapkey也知道了就可以构造返回的dictionary了。 id value = nil; if (propertyMeta->_isCNumber) { value = ModelCreateNumberFromProperty(model, propertyMeta); } elseif (propertyMeta->_nsType) { id v = ((id (*)(id, SEL))(void *) objc_msgSend)((id)model, propertyMeta->_getter); value = ModelToJSONObjectRecursive(v); } else { switch (propertyMeta->_type & YYEncodingTypeMask) { case YYEncodingTypeObject: { id v = ((id (*)(id, SEL))(void *) objc_msgSend)((id)model, propertyMeta->_getter); value = ModelToJSONObjectRecursive(v); if (value == (id)kCFNull) value = nil; } break; case YYEncodingTypeClass: { Class v = ((Class (*)(id, SEL))(void *) objc_msgSend)((id)model, propertyMeta->_getter); value = v ? NSStringFromClass(v) : nil; } break; case YYEncodingTypeSEL: { SEL v = ((SEL (*)(id, SEL))(void *) objc_msgSend)((id)model, propertyMeta->_getter); value = v ? NSStringFromSelector(v) : nil; } break; default: break; } } if (!value) return; //根据是否有_mappedToKeyPath将上面获取到的值加入到字典中。 if (propertyMeta->_mappedToKeyPath) { NSMutableDictionary *superDic = dic; NSMutableDictionary *subDic = nil; for (NSUInteger i = 0, max = propertyMeta->_mappedToKeyPath.count; i < max; i++) { NSString *key = propertyMeta->_mappedToKeyPath[i]; if (i + 1 == max) { // end if (!superDic[key]) superDic[key] = value; break; } subDic = superDic[key]; if (subDic) { if ([subDic isKindOfClass:[NSDictionaryclass]]) { subDic = subDic.mutableCopy; superDic[key] = subDic; } else { break; } } else { subDic = [NSMutableDictionary new]; superDic[key] = subDic; } superDic = subDic; subDic = nil; } } else { if (!dic[propertyMeta->_mappedToKey]) { dic[propertyMeta->_mappedToKey] = value; } } }]; if (modelMeta->_hasCustomTransformToDictionary) { BOOL suc = [((id<YYModel>)model) modelCustomTransformToDictionary:dic]; if (!suc) returnnil; } return result; }
ModelToJSONObjectRecurs代码很长我们分段进行解析:
简单类型
if (!model || model == (id)kCFNull) return model; if ([model isKindOfClass:[NSStringclass]]) return model; if ([model isKindOfClass:[NSNumberclass]]) return model; if ([model isKindOfClass:[NSURLclass]]) return ((NSURL *)model).absoluteString; if ([model isKindOfClass:[NSAttributedStringclass]]) return ((NSAttributedString *)model).string; if ([model isKindOfClass:[NSDateclass]]) return [YYISODateFormatter() stringFromDate:(id)model]; if ([model isKindOfClass:[NSDataclass]]) returnnil;
这部分就不介绍了。
NSDictionary, NSSet,NSArray 容器类型
if ([model isKindOfClass:[NSDictionaryclass]]) { // 简单的字典 if ([NSJSONSerialization isValidJSONObject:model]) return model; // 对象是复杂的对象 NSMutableDictionary *newDic = [NSMutableDictionary new]; [((NSDictionary *)model) enumerateKeysAndObjectsUsingBlock:^(NSString *key, id obj, BOOL *stop) { NSString *stringKey = [key isKindOfClass:[NSStringclass]] ? key : key.description; if (!stringKey) return; //复杂对象需要递归转换 id jsonObj = ModelToJSONObjectRecursive(obj); if (!jsonObj) jsonObj = (id)kCFNull; newDic[stringKey] = jsonObj; }]; return newDic; } //如果当前对象是NSSet if ([model isKindOfClass:[NSSetclass]]) { //..... } //如果当前对象是NSArray if ([model isKindOfClass:[NSArrayclass]]) { //..... }