UIScrollView、UIView、UILabel、UIImageView修改默认值(runtime、Swizzle)

记录使用runtime修改UIScrollview的经历


今天突然发现一个问题,UITableView中添加的几个按钮,点击后push到其他ViewController中,结果按钮的选中效果不显示,查了一下UIScrollView的API,发现了delaysContentTouches这个属性

@property (nonatomic) BOOL delaysContentTouches;// default is YES. if NO, we immediately call -touchesShouldBegin:withEvent:inContentView:. this has no effect on presses

这个属性默认为YES,也就是会延迟发送touchesShouldbegin这个消息,也就导致了按钮的选中效果没有及时显示出来

那么如何设置一下delaysContentTouches这个属性为NO就好了

_scrollView.delaysContentTouches=NO;

bingo,成功!!!

那么问题来了,项目中有很多的TableView、ScrollView、WebView,挨个的去设置ScrollView的这个属性,未免改动太大,而且风险较高,此时我想到了runtime,那么如何用runtime实现这个效果呢,该写到那个方法中呢?

大家都知道+(void)load和+(void)initialize方法的吧,通俗解释就是load和initialize都是在类加载进内存的时候就会执行,也就是说在main函数调用之前执行。

题外话:load和initialize两个方法都不在main函数的autoreleasepool中,是在main函数之前加载到内存中的,所以,对于这两个方法内初始化的私有变量需要程序员们来处理,怎么处理呢?ARC的话只需要@autoreleasepool封装就好了

我们选择在load中实现,首先因为initialize是在该类或者类对象被调用的时候才会执行,其次,initialize只会调用一次,而且我们要用category实现,类的每一个category类中都会执行各自的load类方法;再者,load我们要对默认值进行修改,应当尽量提前的替换掉方法块才可以

废话不多说,上代码

+ (void)load {

        static dispatch_once_t onceToken;

        dispatch_once(&onceToken, ^{

                Class class = [self class];

                SEL originInitSel = @selector(initWithFrame:);

                SEL newInitSel = @selector(xxxx_initWithFrame:);

                Method originalMethod = class_getInstanceMethod(class, originInitSel);

                Method swizzledMethod = class_getInstanceMethod(class, newInitSel);

                BOOL didAddMethod =class_addMethod(class,originInitSel,method_getImplementation(swizzledMethod),method_getTypeEncoding(swizzledMethod));

                if (didAddMethod) {

                        class_replaceMethod(class,newInitSel,method_getImplementation(originalMethod),method_getTypeEncoding(originalMethod));

                } else {

                        method_exchangeImplementations(originalMethod, swizzledMethod);

                }

    });

}

/**

重置系统的默认值

让scrollview中的按钮可以随时显示按钮的按下动作

**/

- (id)xxxx_initWithFrame:(CGRect)frame{

        UIScrollView* vscroll = [self xxxx_initWithFrame:frame];///一定要注意这里

        vscroll.delaysContentTouches = NO;

        return vscroll;

}

@end

盗用其他同学的图片:


这是苹果的消息传递的概要原理


这是Swizzle的概要原理

我在这里也描述一下我个人的理解:

1.在编译阶段,llvm会生成一个方法名(字符串、SEL)、类(字符串、class name)和函数指针(IMP)之间的映射表(hashtable)

2.消息传递的概要过程:

    通过方法名(SEL)查找对应的函数指针(IMP)

3.调用方法块(IMP)

那么Swizzle其实就是变更了方法名(SEL)和函数指针(IMP)之间的映射关系。

其实理解起来很简单~不明白的小伙伴可以在评论区交流一下,欢迎拍砖

UIView/UIImageView也可以用类似的方法修改任意的默认值咯


疑问:在我们的iOS开发过程中,如果一个类方法非常多,加载类到内存的时候也比较耗费资源,需要给每个方法生成映射表,可以使用动态给某个类,添加方法解决。做到优化内存,节省资源的效果,这是为什么呢?

我的qq是:58901119 多交流哟~

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

  • 转至元数据结尾创建: 董潇伟,最新修改于: 十二月 23, 2016 转至元数据起始第一章:isa和Class一....
    40c0490e5268阅读 5,883评论 0 9
  • 继上Runtime梳理(四) 通过前面的学习,我们了解到Objective-C的动态特性:Objective-C不...
    小名一峰阅读 4,145评论 0 3
  • 我们常常会听说 Objective-C 是一门动态语言,那么这个「动态」表现在哪呢?我想最主要的表现就是 Obje...
    Ethan_Struggle阅读 6,614评论 0 7
  • 这篇文章完全是基于南峰子老师博客的转载 这篇文章完全是基于南峰子老师博客的转载 这篇文章完全是基于南峰子老师博客的...
    西木阅读 30,756评论 33 466
  • 转载:http://yulingtianxia.com/blog/2014/11/05/objective-c-r...
    F麦子阅读 4,127评论 0 2

友情链接更多精彩内容