老生常谈 之runtime!

runtime!runtime! runtime! 几乎每个iOS开发从业者在面试时都会被问到什么是runtime?!有什么用?!介于本人的一点从业经验和过往学习,下面就runtime做一个简单粗暴的介绍。

Objective-C 语言是一门动态语言,编译器不需要关心接受消息的对象是何种类型,接收消息的对象问题也要在运行时处理。

pragramming 层面的 runtime 主要体现在以下几个方面:

关联对象Associated Objects

消息发送Messaging

消息转发Message Forwarding

方法调配Method Swizzling

“类对象” NSProxyFoundation | Apple Developer Documentation

KVC、KVOAbout Key-Value Coding

补充一个大家经常用的、但是很容易忽视的 runtime 应用吧:

动态获取 class 和 slector

NSClassFromString(@"MyClass");NSSelectorFromString(@"showShareActionSheet");

给分类添加属性KVC/KVO了。

大多数情况下,我们是不会直接用 runtime 写业务代码的,所以,大部分时候,我们只会在一些平时用起来很方便的框架里面,看到有用到 runtime 的黑魔法(当然你也可以自己造轮子)。runtime 用起来的最大感受就是,底层写一堆 runtime,外面用起来超清爽!对于那些“代码艺术家”来说,简直是爽到爆。

我在项目中使用runtime比较少:

1.在category中添加属性

2.修改系统方法,如重写objectAtIndex方法阻止数组越界崩溃。

大概说说一下自己在开发中用到的一些基于 runtime 的开源框架吧,具体应用自己可以去看看源码:

1.Aspects(AOP必备,“取缔” baseVC,无侵入埋点)

2.MJExtension(JSON 转 model,一行代码实现 NSCoding 协议的自动归档和解档)

3.JSPatch(动态下发 JS 进行热修复)

4.NullSafe(防止因发 unrecognised messages 给 NSNull 导致的崩溃)

5.UITableView-FDTemplateLayoutCell(自动计算并缓存 table view 的 cell 高度)

6.UINavigationController+FDFullscreenPopGesture(全屏滑动返回)

runtime 的原理和用法可以看看官方文档

Objective-C Runtime Programming GuideInteracting with the Runtime

Objective-C Runtime Reference

About Key-Value Coding

Introduction to Key-Value Observing Programming Guide

20180212  更新

在引导页上使用了runtime

.h代码如下:

#import<UIKit/UIKit.h>@interfaceUIViewController(KSGuid)//*实现引导页的控制器,外部不用调用即可实现GuidView,可以修改下面的图片*/@end/*这里是要展示的图片,修改即可,当然不止三个  1242 * 2208的分辨率最佳,如果在小屏手机上显示不全,最好要求UI重新设计图片*/#define ImageArray @[@"guid01",@"guid02",@"guid03",@"guid04"]/** pageIndicatorTintColor*/#define pageTintColor [[UIColor whiteColor] colorWithAlphaComponent:0.5];/** currentPageIndicatorTintColor*/#define currentTintColor [UIColor whiteColor];/*

如果要修改立即体验按钮的样式

重新- (UIButton*)removeBtn方法即可

*/

.m代码如下

#import"UIViewController+KSGuid.h"#import<objc/runtime.h>#define CollectionView_Tag 15#define RemoveBtn_tag 16#define Control_tag 17#define FIRST_IN_KEY @"FIRST_IN_KEY"@interfaceKSGuidViewCell:UICollectionViewCell@property(nonatomic,copy)NSString* imageName;@property(nonatomic,strong)UIImageView* imageView;@end@implementationKSGuidViewCell- (instancetype)initWithFrame:(CGRect)frame{self= [superinitWithFrame:frame];if(self) {        _imageView = [[UIImageViewalloc] initWithFrame:self.bounds];        _imageView.contentMode =UIViewContentModeScaleAspectFill;        _imageView.userInteractionEnabled =YES;        [self.contentView addSubview:_imageView];    }returnself;}- (void)setImageName:(NSString*)imageName{if(_imageName != imageName) {        _imageName = [imageNamecopy];    }    _imageView.image = [UIImageimageNamed:imageName];}@end/************************以上是KSGuidViewCell,以下才是UIViewController+KSGuid******************************/@implementationUIViewController(KSGuid)#pragma mark- #pragma mark 这里是退出的按钮- (UIButton*)removeBtn{//移除按钮样式UIButton* removeBtn = [UIButtonbuttonWithType:UIButtonTypeCustom];    [removeBtn addTarget:selfaction:@selector(removeGuidView) forControlEvents:UIControlEventTouchUpInside];    removeBtn.hidden = (self.imageArray.count !=1);    removeBtn.tag = RemoveBtn_tag;//注意这里的tag//***********************这里面可以自定义*******************************//CGFloatbtnW =128;CGFloatbtnH =35;CGFloatbtnX =CGRectGetMidX(self.view.frame) - btnW /2;CGFloatbtnY =CGRectGetMaxY(self.view.frame) *0.83;    removeBtn.frame =CGRectMake(btnX, btnY, btnW, btnH);        removeBtn.layer.cornerRadius =4;    removeBtn.layer.borderColor = [UIColorwhiteColor].CGColor;    removeBtn.layer.borderWidth =1.;        [removeBtn setTitle:@"进入婚匠"forState:UIControlStateNormal];    [removeBtn setTitleColor:[UIColorwhiteColor] forState:UIControlStateNormal];    removeBtn.titleLabel.font = [UIFontsystemFontOfSize:18.];//********************自定义结束**********************************//returnremoveBtn;}#pragma mark-#pragma mark 这里填充图片的名称- (NSArray*)imageArray{returnImageArray;}+ (void)load{NSString* versoin = [[[NSBundlemainBundle] infoDictionary] objectForKey:@"CFBundleShortVersionString"];NSString* versionCache = [[NSUserDefaultsstandardUserDefaults] objectForKey:FIRST_IN_KEY];//启动时候首先判断是不是第一次if([versoin isEqualToString:versionCache]) {return;    }//以下代码只在程序安装初次运行时候执行staticdispatch_once_tonceToken;dispatch_once(&onceToken, ^{                Method method1 = class_getInstanceMethod(self.class,@selector(viewDidLoad));        Method method2 = class_getInstanceMethod(self.class,@selector(guidViewDidLoad));BOOLdidAddMethod =        class_addMethod(self.class,@selector(viewDidLoad),                        method_getImplementation(method2),                        method_getTypeEncoding(method2));if(didAddMethod) {            class_replaceMethod(self.class,@selector(guidViewDidLoad),                                method_getImplementation(method1),                                method_getTypeEncoding(method1));        }else{            method_exchangeImplementations(method1, method2);        }    });}- (void)guidViewDidLoad{staticdispatch_once_tonceToken;dispatch_once(&onceToken, ^{//这里的代码只在程序安装初次打开,并且在第一个控制器里面执行//初始化视图[selfsetupSubViews];    });//这是调用工程里面的viewDidLoad[selfguidViewDidLoad];}#pragma mark- #pragma mark 初始化视图- (void)setupSubViews{//界面样式UICollectionViewFlowLayout* flowLayout = [[UICollectionViewFlowLayoutalloc] init];    flowLayout.itemSize = [UIScreenmainScreen].bounds.size;    flowLayout.minimumLineSpacing =0;    flowLayout.minimumInteritemSpacing =0;    flowLayout.sectionInset =UIEdgeInsetsZero;    flowLayout.scrollDirection =UICollectionViewScrollDirectionHorizontal;UICollectionView* collectionView = [[UICollectionViewalloc]                      initWithFrame:self.view.bounds                      collectionViewLayout:flowLayout];    collectionView.dataSource =self;    collectionView.delegate =self;    collectionView.pagingEnabled =YES;    collectionView.showsVerticalScrollIndicator =NO;    collectionView.showsHorizontalScrollIndicator =NO;    collectionView.backgroundColor = [UIColorwhiteColor];    [collectionView registerClass:[KSGuidViewCellclass] forCellWithReuseIdentifier:@"KSGuidViewCell"];        collectionView.tag = CollectionView_Tag;    [self.view addSubview:collectionView];        [self.view addSubview:self.removeBtn];UIPageControl* control = [[UIPageControlalloc] init];CGFloatcontrolW =170;CGFloatcontrolH =20;CGFloatcontrolX =CGRectGetMidX(self.view.frame) - controlW /2;CGFloatcontrolY =CGRectGetMaxY(self.view.frame) -38;    control.frame =CGRectMake(controlX, controlY, controlW, controlH);    control.numberOfPages = ImageArray.count;    control.pageIndicatorTintColor = pageTintColor;    control.currentPageIndicatorTintColor = currentTintColor;        control.tag = Control_tag;    [self.view addSubview:control];}#pragma mark-#pragma mark UICollectionViewDataSource- (NSInteger)collectionView:(UICollectionView*)collectionView numberOfItemsInSection:(NSInteger)section{returnself.imageArray.count;}- (UICollectionViewCell*)collectionView:(UICollectionView*)collectionView cellForItemAtIndexPath:(NSIndexPath*)indexPath{        KSGuidViewCell* cell = [collectionView dequeueReusableCellWithReuseIdentifier:@"KSGuidViewCell"forIndexPath:indexPath];    cell.imageName =self.imageArray[indexPath.row];returncell;}- (void)scrollViewDidScroll:(UIScrollView*)scrollView{NSUIntegerindex = scrollView.contentOffset.x /CGRectGetWidth(self.view.frame);    [self.view viewWithTag:RemoveBtn_tag].hidden = (index !=self.imageArray.count -1);UIPageControl* control =[self.view viewWithTag:Control_tag];    control.currentPage = index;    }- (void)removeGuidView{NSString* versoin = [[[NSBundlemainBundle] infoDictionary] objectForKey:@"CFBundleShortVersionString"];    [[NSUserDefaultsstandardUserDefaults] setObject:versoin forKey:FIRST_IN_KEY];    [[NSUserDefaultsstandardUserDefaults] synchronize];        [[self.view viewWithTag:Control_tag] removeFromSuperview];    [[self.view viewWithTag:RemoveBtn_tag] removeFromSuperview];    [[self.view viewWithTag:CollectionView_Tag] removeFromSuperview];}@end

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 202,980评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,178评论 2 380
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 149,868评论 0 336
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,498评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,492评论 5 364
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,521评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,910评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,569评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,793评论 1 296
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,559评论 2 319
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,639评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,342评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,931评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,904评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,144评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,833评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,350评论 2 342

推荐阅读更多精彩内容