美文网首页
SDWebImage知识点总结二

SDWebImage知识点总结二

作者: woniu | 来源:发表于2018-05-28 18:34 被阅读25次
“宜未雨而绸缪;毋临渴而掘井。”凡事早做打算,方为上上之策!------前言

一、SDWebImage中的weakself&strongself

//#import "SDWebImageDownloaderOperation.h"
if (hasApplication && [self shouldContinueWhenAppEntersBackground]) {
            __weak __typeof__ (self) wself = self;
            UIApplication * app = [UIApplicationClass performSelector:@selector(sharedApplication)];
            self.backgroundTaskId = [app beginBackgroundTaskWithExpirationHandler:^{
                __strong __typeof (wself) sself = wself;

                if (sself) {
                    [sself cancel];

                    [app endBackgroundTask:sself.backgroundTaskId];
                    sself.backgroundTaskId = UIBackgroundTaskInvalid;
                }
            }];
        }

疑问:

1、为什么使用weakSelf?

因为Block是一个结构体,它会将一个全局变量保存为一个属性(__strong),而self强引用了Block这会造成循环引用,所以使用__weak修饰weakSelf。

2、为什么在Block里面使用strongSelf?

为了保证block在执行完毕之前self不会被释放,而strongSelf是为了保证Block内部执行的时候不会被释放,但是存在执行前就已经被释放的情况,导致strongSelf=nil。注意判空处理,防止出现崩溃。typeof是编译时确定变量类型,所以这里写self 不会被循环引用。

总结:

外部使用了weakSelf,里面使用strongSelf却不会造成循环,究其原因就是因为weakSelf是block截获的属性,而strongSelf是一个局部变量会在“函数”执行完释放。

扩展1:

1、__block可以让block修改局部变量,而__weak不能。
2、MRC中__block是不会引起retain;但在ARC中__block则会引起retain,因为,block也是一个强引用,引起循环引用,会引起循环引用。所以ARC中应该使用__weak。

扩展2:

  • 什么情况下Block不循环引用呢?
    以下三种情况都是单向“强引用”,只是Block持有self,但self并没有持有block,所以不用考虑“循环引用”的问题。
    1、UIView动画
[UIView animateWithDuration:duration animations:^{ [self.superview layoutIfNeeded]; }]; 

2、NSNotification

[[NSNotificationCenter defaultCenter] addObserverForName:@"someNotification" 
                                                 object:nil 
                          queue:[NSOperationQueue mainQueue]
                                             usingBlock:^(NSNotification * notification) {
                                                   self.someProperty = xyz; }]; 

3、NSOperation

[[NSOperationQueue mainQueue] addOperationWithBlock:^{ self.someProperty = xyz; }]; 

二、SDWebImage为类别添加属性

类别本身不允许为已有的类添加属性,及时你使用@property添加属性,这个属性也是无法使用的,因为它是不会生成setter/getter方法。为了解决这个问题,我们可以使用runtime来为类别添加新的属性并手动生成setter/getter方法。

/*
     objc_AssociationPolicy参数使用的策略:
     OBJC_ASSOCIATION_ASSIGN;            //assign策略
     OBJC_ASSOCIATION_COPY_NONATOMIC;    //copy策略
     OBJC_ASSOCIATION_RETAIN_NONATOMIC;  // retain策略
     
     OBJC_ASSOCIATION_RETAIN;
     OBJC_ASSOCIATION_COPY;
     */
//#import "UIImageView+WebCache.h"
static char imageURLKey;
static char TAG_ACTIVITY_INDICATOR;
static char TAG_ACTIVITY_STYLE;
static char TAG_ACTIVITY_SHOW;

- (UIActivityIndicatorView *)activityIndicator {
    return (UIActivityIndicatorView *)objc_getAssociatedObject(self, &TAG_ACTIVITY_INDICATOR);
}
    // 参数1:源对象
    // 参数2:关联时用来标记属性的key(因为可能要添加很多属性)
    // 参数3:关联的对象
    // 参数4:关联策略
    // 关联方法
- (void)setActivityIndicator:(UIActivityIndicatorView *)activityIndicator {
    objc_setAssociatedObject(self, &TAG_ACTIVITY_INDICATOR, activityIndicator, OBJC_ASSOCIATION_RETAIN);
}

- (void)setShowActivityIndicatorView:(BOOL)show{
    objc_setAssociatedObject(self, &TAG_ACTIVITY_SHOW, [NSNumber numberWithBool:show], OBJC_ASSOCIATION_RETAIN);
}

- (BOOL)showActivityIndicatorView{
    return [objc_getAssociatedObject(self, &TAG_ACTIVITY_SHOW) boolValue];
}

runtime增加对象属性

Category为什么可以添加方法,而不可以添加成员变量?
struct objc_class {
    Class isa  OBJC_ISA_AVAILABILITY;
#if !__OBJC2__
    Class super_class                       OBJC2_UNAVAILABLE;  // 父类
    const char *name                        OBJC2_UNAVAILABLE;  // 类名
    long version                            OBJC2_UNAVAILABLE;  // 类的版本信息,默认为0
    long info                               OBJC2_UNAVAILABLE;  // 类信息,供运行期使用的一些位标识
    long instance_size                      OBJC2_UNAVAILABLE;  // 该类的实例变量大小
    struct objc_ivar_list *ivars            OBJC2_UNAVAILABLE;  // 该类的成员变量链表
    struct objc_method_list **methodLists   OBJC2_UNAVAILABLE;  // 方法定义的链表
    struct objc_cache *cache                OBJC2_UNAVAILABLE;  // 方法缓存
    struct objc_protocol_list *protocols    OBJC2_UNAVAILABLE;  // 协议链表
#endif
} OBJC2_UNAVAILABLE;
  • 在objc_class结构体中,ivars是objc_ivar_list指针(成员变量链表);methodLists是指向objc_method_list指针的指针(注意是:**)。
  • 在runtime中,objc_class结构体的大小是固定的,不可能向这个结构体中添加数据,只能修改。
  • ivars指向的是一个固定区域,只能修改成员变量的值,而不能增加成员变量的个数。
  • iMethodList是一个二维数组,所以可以修改methodLists的值来增加成员方法,虽然没办法扩展MethodList的内存区域,但是可以改变这个内存区域的值(存储的是指针)。
  • 因此,可以动态添加方法,不能添加成员变量。
    RunTime基本概念

三、SDWebImage中的断言NSAssert

在iOS开发中,可以使用宏NSAssert()在程序中进行断言处理。NSAssert()使用正确,可以帮助开发者尽快定位bug。

//#import "SDWebImageManager.h"
NSAssert(completedBlock != nil, @"If you mean to prefetch the image, use -[SDWebImagePrefetcher prefetchURLs] instead");
  • NSAssert实际示例
- (void)printMyName:(NSString *)myName  
{  
    NSAssert(myName != nil, @"名字不能为空!");  
    NSLog(@"My name is %@.",myName);  
}  

当传给函数的参数(myName)为空时,断言将被执行,程序Crash,并打印出断言中的描述信息。本例中,在控制台打印出了如下的日志:

2018-05-29 11:25:46.846909+0800 autoReleasePoolTest[78930:6611559] *** Assertion failure in -[ViewController printMyName:], /Users/zhangzhangkai/Library/Autosave Information/autoReleasePoolTest/autoReleasePoolTest/ViewController.m:55
2018-05-29 11:25:46.861768+0800 autoReleasePoolTest[78930:6611559] *** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: '名字不能为空!'

断言(NSAssert)的使用

四、SDWebImage中GCD的使用

  • 设置栅栏,阻塞线程,实现线程同步。dispatch_barrier_sync必须在并行队列且是创建的用户队列(dispatch_queue_t)中才能实现其“栅栏”的功能。
    栅栏:在栅栏之前的队列先执行,然后执行栅栏,最后再执行栅栏之后的队列。它其实起到一个分割的作用。我们可以用它来实现GCD的同步。
GCD实现线程同步的方法:
  • 组队列(dispatch_group)
  • 阻塞任务(dispatch_barrier)
  • 信号量机制(dispatch_semaphore)
@property (SDDispatchQueueSetterSementics, nonatomic) dispatch_queue_t barrierQueue;

 __block NSArray *callbacksForURL;
  dispatch_barrier_sync(sself.barrierQueue, ^{
   callbacksForURL = [sself.URLCallbacks[url] copy];
    if (finished) {
    [sself.URLCallbacks removeObjectForKey:url];
     }
    });

【iOS沉思录】GCD实现线程同步的方法
GCD剖析

五、内联函数inline

inline定义:内联函数是指用inline关键字修饰的函数。内联函数不是在调用时发生控制转移,而是在编译时将函数体嵌入在每一个调用处。编译时,类似宏替换,使用函数体替换调用处的函数名。
  • extern关键字声明的对象为整个项目使用。
  • inline内联函数,作用代替宏。
inline内联函数的说明
  • 1.内联函数只是我们向编译器提供的申请,编译器不一定采取inline形式调用函数.
  • 2.内联函数不能承载大量的代码.如果内联函数的函数体过大,编译器会自动放弃内联.
  • 3.内联函数内不允许使用循环语句或开关语句.
  • 4.内联函数的定义须在调用之前.
为什么inline能取代宏?
  • 优点相比于函数:
    1、inline函数避免了普通函数的,在汇编时必须调用call的缺点:取消了函数的参数压栈,减少了调用的开销,提高效率.所以执行速度确比一般函数的执行速度要快.
    2、集成了宏的优点,使用时直接用代码替换(像宏一样);

  • 优点相比于宏:
    1、避免了宏的缺点:需要预编译.因为inline内联函数也是函数,不需要预编译.
    2、编译器在调用一个内联函数时,会首先检查它的参数的类型,保证调用正确。然后进行一系列的相关检查,就像对待任何一个真正的函数一样。这样就消除了它的隐患和局限性。
    3、可以使用所在类的保护成员及私有成员。
    OC内联函数传送门
    内联函数在开发中的应用

extern UIImage *SDScaledImageForKey(NSString *key, UIImage *image);

//#import "SDWebImageCompat.h"
inline UIImage *SDScaledImageForKey(NSString *key, UIImage *image) {
    if (!image) {
        return nil;
    }
    
    if ([image.images count] > 0) {
        NSMutableArray *scaledImages = [NSMutableArray array];

        for (UIImage *tempImage in image.images) {
            [scaledImages addObject:SDScaledImageForKey(key, tempImage)];
        }

        return [UIImage animatedImageWithImages:scaledImages duration:image.duration];
    }
    else {
        if ([[UIScreen mainScreen] respondsToSelector:@selector(scale)]) {
            CGFloat scale = 1;
            if (key.length >= 8) {
                NSRange range = [key rangeOfString:@"@2x."];
                if (range.location != NSNotFound) {
                    scale = 2.0;
                }
                
                range = [key rangeOfString:@"@3x."];
                if (range.location != NSNotFound) {
                    scale = 3.0;
                }
            }

            UIImage *scaledImage = [[UIImage alloc] initWithCGImage:image.CGImage scale:scale orientation:image.imageOrientation];
            image = scaledImage;
        }
        return image;
    }
}

六、iOS网络请求NSURLSession

NSURLSession

使用方法介绍

七、clang diagnostic的使用

SDWebImage中SDWebImageDownloader.m中的设置如下:

#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Warc-performSelector-leaks"
        id activityIndicator = [NSClassFromString(@"SDNetworkActivityIndicator") performSelector:NSSelectorFromString(@"sharedActivityIndicator")];
#pragma clang diagnostic pop

看到这里我也是一头雾水,不明所以。查过资料之后发现,clang为诊断设置,辅助我们编码。
-Warc-performSelector-leaks的解释为“performSelector may cause a leak because its selector is unknown”因为方法位置,所以可能会导致泄漏。这里就是忽略这个告警,SDWebImage作者八成是个处女座。

  • 使用模式如下:
#pragma clang diagnostic push  
#pragma clang diagnostic ignored "-相关命令"  
    // 你自己的代码  
#pragma clang diagnostic pop  

栗子1:忽略弃用的警告⚠️

//1、如果直接写已经废弃的方法会报警
UIAlertView *alertView = [[UIAlertView alloc]initWithTitle:@"" message:@"" delegate:nil cancelButtonTitle:@"" otherButtonTitles:@"", nil];
[alertView show]

//2、忽略方法弃用告警    
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
    UIAlertView *alertViewTmp = [[UIAlertView alloc]initWithTitle:@"" message:@"" delegate:nil cancelButtonTitle:@"" otherButtonTitles:@"", nil];
    [alertViewTmp show];
#pragma clang diagnostic pop

栗子2:忽略不兼容指针类型⚠️

//   不兼容指针类型 
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wincompatible-pointer-types"
    //
#pragma clang diagnostic pop

栗子3:循环引用⚠️

break the retain cycle.
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Warc-retain-cycles"
//    self.completionBlock = ^ {
//        ...
//    };
#pragma clang diagnostic pop

栗子4:未使用变量 ⚠️

// 未使用变量   
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wunused-variable"
    int a;
#pragma clang diagnostic pop
告警使用列表

clang diagnostic的使用
告警使用列表注释

相关文章

  • iOS复习中有关SDWebImage可能知识点总结

    iOS复习中有关SDWebImage可能知识点总结 iOS复习中有关SDWebImage可能知识点总结

  • SDWebImage知识点总结二

    “宜未雨而绸缪;毋临渴而掘井。”凡事早做打算,方为上上之策!------前言 一、SDWebImage中的weak...

  • SDWebImage知识点总结一

    目不能两视而明,耳不能两听而聪。----------《荀子·劝学》 技术点归纳 与图片相关的,这些知识都是与图片相...

  • SDWebImage使用

    SDWebImage的使用 SDWebImage的所有的下载策略 SDWebImage实现逻辑分析 总结一下: 主...

  • IOS之SDWebImage(附Demo)

    目录 一、SDWebImage安装集成 二、SDWebImage原理说明 三、SDWebImage源码实现步骤 四...

  • SDWebImage4.0源码探究(一)面试题

    目录 一、SDWebImage UML分析 二、SDWebImage 中 @autoreleasepool 的应用...

  • SDWebImage 知识点

    1、取消当前的下载操作 如果不取消,那么当tableView滑动的时候,当前cell的imageView会一直去下...

  • SDWebImage知识点

    SDWebImage的缓存策略 SDWebImage 的图片缓存默认情况采用的是 Memory 和 Disk 双重...

  • 无标题文章

    综和复习本月知识点总结: 一:微信小程序 二:vue复习 三:js复习 四:新知识点 一:微信小程序知识点总结 开...

  • SDWebImage源码学习(一) --- SDWebImage

    第一步还是先学习SDWebImage中还不怎么熟悉的知识点 知识点1 --- #error 用来做显示编译出错内容...

网友评论

      本文标题:SDWebImage知识点总结二

      本文链接:https://www.haomeiwen.com/subject/estnjftx.html