iOS RunTime你知道了总得用一下
说点题外话:
我刚来现在这家公司的时候,老板让我下载一个脉脉,上去找找自己的同行,多认识些同行。其实初衷的好的,但最近这两天我把它卸载了,不为别的,负能量太多!iOS这行自从2016就没景气过,在这行混,这些自己也肯定都知道。但就是受不鸟铺天盖地的多久没找到工作,满大街都是iOS程序猿这些话题。看了也给我带不来任何的作用,你唯一能做的就是安安静静的做好自己该做的。自己入iOS这行也一年半过了,除去培训的那个几个月,真正摸爬滚打也一年多了,有时候想想,其实也没觉得有多差,以后怎样不知道,但至少现在,你有份工作,有口饭吃,还有时间给你去学习,有什么不知足的呢?在我自己浅薄的意识里,编程思想都是相同的,喜欢iOS你也可能也会喜欢安卓,Java,JS,PHP等等等。。活到老,学到老,那颗不停的去学的心就是自己最大的依靠。
回归正题:
以前有了解过Runtime,不记得是几个月前的事情了,最近又遇到这个问题,还是总结一下吧,总结的不好的地方,见谅了。。
Runtime俗称“运行时”,项目都有分一个编译和运行两个状态,这个应该了解。是一套底层的C语言的API。OC是一门动态的语言,有些东西不会放在我们编译的时候去处理,会等到运行时去处理。下面说的这些,建议大家随表这个项目,导入下面头文件点进去我们一起慢慢探讨!
#import <objc/runtime.h>
看看他最上面:
/// An opaque type that represents a method in a class definition.
typedef struct objc_method *Method; // 方法 /// An opaque type that represents an instance variable.
typedef struct objc_ivar *Ivar; // 变量 /// An opaque type that represents a category.
typedef struct objc_category *Category; // 类别也叫分类 /// An opaque type that represents an Objective-C declared property.
typedef struct objc_property *objc_property_t; // 属性
定义在上面代码的注释里我们说了,再往下看你就看到的是类的表示:
struct objc_class {
Class isa OBJC_ISA_AVAILABILITY; #if !__OBJC2__
Class super_class OBJC2_UNAVAILABLE;
const char *name OBJC2_UNAVAILABLE;
long version OBJC2_UNAVAILABLE;
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;
/* Use `Class` instead of `struct objc_class *` */
Class super_class指向父类。
const char *name 类的名字long version 类的版本信息,初始化默认为0,下面有函数class_setVersion和class_getVersion可以对它进行进行修改和读
long info 标识。
long instance_size 类的实例变量的大小,包括继承的父类的。
struct objc_ivar_list *ivars 成员变量的地址。
struct objc_method_list **methodLists
struct objc_cache *cache 指向最近使用的方法的指针struct objc_protocol_list *protocols 遵守的协议。
下面就是一系列的方法了,这里总结常见的,在下面的代码注释里面会说的比较详细点:
#import "ViewController.h"
#import <objc/runtime.h>
/**
* 定义一个测试的协议
*/
@protocol protocolTestDelegate <NSObject>
@optional -(void)protocolTestDelegate;
@end
@interface ViewController ()
/**
* 定义三个测试的属性
*/
@property (nonatomic,strong) NSString * testString1;
@property (nonatomic,strong) NSString * testString2;
@property (nonatomic,strong) NSString * testString3;
@end
@implementation ViewController -(void)viewDidLoad { [super viewDidLoad];
/**
* 定义三个测试的成员变量
*/
NSString * Stringone;
NSString * Stringtwo;
NSString * Stringthree;
unsigned int count; // OBJC_EXPORT objc_property_t *class_copyPropertyList(Class cls, unsigned int *outCount)
// 下面是官方的注释,大概翻译;
/**
描述一个类的属性列表
* Describes the properties declared by a class.
*
* @param cls The class you want to inspect.
参数 outCount这个参数是返回了你这个属性列表数组的长度
* @param outCount On return, contains the length of the returned array.
* If \e outCount is \c NULL, the length is not returned.
*
这个方法返回的是一个属性的列表数组
* @return An array of pointers of type \c objc_property_t describing the properties
* declared by the class. Any properties declared by superclasses are not included.
返回的数组包含的 outCount 指针用NULL结尾的,必须释放这个array用free()
* The array contains \c *outCount pointers followed by a \c NULL terminator. You must free the array with \c free().
*
* If \e cls declares no properties, or \e cls is \c Nil, returns \c NULL and \c *outCount is \c 0.
*/
// 这里传的是 &count ,是 count 的地址,outCount是返回的数组的长度的指针,传值就传变量的地址,系统就把长度返回给了这个变量
// 属性
objc_property_t * propertyList = class_copyPropertyList([self class],&count);
for (unsigned int i = 0; i<count; i++) { // objc_property_t property
// (nonnull const char *)
const char * property = property_getName(propertyList[i]);
NSLog(@"property %@",[NSString stringWithUTF8String:property]);
}
/**
* 打印
2016-08-29 11:37:03.302 RunTimeTest[10078:132260] property testString1
2016-08-29 11:37:03.303 RunTimeTest[10078:132260] property testString2
2016-08-29 11:37:03.303 RunTimeTest[10078:132260] property testString3
*/
// 方法
Method * methontList = class_copyMethodList([self class], &count);
for (unsigned int i = 0 ; i<count; i++) { Method methond = methontList[i];
NSLog(@"methond %@",NSStringFromSelector(method_getName(methond))); }
/**
*
2016-08-29 14:01:30.458 RunTimeTest[16581:201546] methond ClassTestone
2016-08-29 14:01:30.458 RunTimeTest[16581:201546] methond ClassTesttwo
2016-08-29 14:01:30.459 RunTimeTest[16581:201546] methond ClassTesthree
2016-08-29 14:01:30.459 RunTimeTest[16581:201546] methond testString1 // testString1 get方法
2016-08-29 14:01:30.459 RunTimeTest[16581:201546] methond setTestString1:
2016-08-29 14:01:30.459 RunTimeTest[16581:201546] methond testString2
2016-08-29 14:01:30.459 RunTimeTest[16581:201546] methond setTestString2:
2016-08-29 14:01:30.459 RunTimeTest[16581:201546] methond testString3
2016-08-29 14:01:30.459 RunTimeTest[16581:201546] methond setTestString3:
2016-08-29 14:01:30.459 RunTimeTest[16581:201546] methond .cxx_destruct //
2016-08-29 14:01:30.459 RunTimeTest[16581:201546] methond didReceiveMemoryWarning
2016-08-29 14:01:30.460 RunTimeTest[16581:201546] methond viewDidLoad
*/
// 成员变量
Ivar * ivarList = class_copyIvarList([self class], &count);
for (unsigned int i =0 ; i<count; i++) { Ivar ivar = ivarList[i];
const char *ivarName = ivar_getName(ivar);
NSLog(@"Ivar %@",[NSString stringWithUTF8String:ivarName]);
}
/**
*
2016-08-29 14:12:17.750 RunTimeTest[17233:209405] Ivar _testString1
2016-08-29 14:12:17.751 RunTimeTest[17233:209405] Ivar _testString2
2016-08-29 14:12:17.751 RunTimeTest[17233:209405] Ivar _testString3
*/
__unsafe_unretained Protocol **protocolListm = class_copyProtocolList([self class], &count);
for (unsigned int i =0 ; i<count; i++) { Protocol * myprotocal = protocolListm[i];
const char * protocalname = property_getName((__bridge objc_property_t)(myprotocal));
NSLog(@"protocal %@",[NSString stringWithUTF8String:protocalname]);
}
// Do any additional setup after loading the view, typically from a nib.
}
/**
* 定义三个测试的方法
*/
-(void)ClassTestone{
NSLog(@"i am the viewcontroller methond");
}
-(void)ClassTesttwo{
}
-(void)ClassTesthree{
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
@end
还有许多:
其实细说这块的只是还有很多,像方法交换 、动态添加方法 、拦截调用等等等,但这个不能乱吹,我项目中暂时也没用过,以后可能会用到吧,现在有导航栏渐变这样的效果,把代码给出来!
给UINavigationBar添加一个类别:
#import <objc/runtime.h>
#import "UINavigationBar+Background.h"
@implementation UINavigationBar (Background) // 给UINavigationBar添加动态属性
static char BackgroundKey;
-(UIView *) BackgroundView
{
return objc_getAssociatedObject(self, &overlayKey);
} -(void)setOverlay:(UIView *) BackgroundView
{
objc_setAssociatedObject(self, &BackgroundKey, BackgroundView, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
} - (void)NASetBackgroundColor:(UIColor *)backgroundColor
{ if (!self. BackgroundView) { [self setBackgroundImage:[UIImage new] forBarMetrics:UIBarMetricsDefault];
self. BackgroundView = [[UIView alloc] initWithFrame:CGRectMake(0, -20, [UIScreen mainScreen].bounds.size.width, CGRectGetHeight(self.bounds) + 20)]; // 比导航高二十,遮住状态栏
self. BackgroundView.userInteractionEnabled = NO;
self. BackgroundView.autoresizingMask = UIViewAutoresizingFlexibleWidth|UIViewAutoresizingFlexibleHeight;
// 给导航添加一个运行时属性.uiview类型。。放置在导航的最上面
[self insertSubview:self. BackgroundView atIndex:0];
}
self. BackgroundView.backgroundColor = backgroundColor;
} -(void)cnReset
{
[self setBackgroundImage:nil forBarMetrics:UIBarMetricsDefault];
[self. BackgroundView removeFromSuperview];
self. BackgroundView = nil;
} @end
然后在 UIScrollViewDelegate 的代理方法里面:
- (void)scrollViewDidScroll:(UIScrollView *)scrollView
{
// 本质是让导航栏添加的BackgroundView属性根据你的scrollView的滑动范围改变颜色
[self.navigationController.navigationBar NASetBackgroundColor:[color colorWithAlphaComponent:alpha]]; }
这是在网上看到的一个效果,就是这种导航栏的渐变:
2018年3月30日
翻到这篇以前的博客文章,是16年的了,现在看两年前的东西可能会稍微有点年代感,总结的也是自己刚在慢慢理解Runtime这个东西的时候写的,哈哈哈,虽然内容现在看值一毛钱,但好处是就像最开始时候说的那样从未停止过脚步,哈哈哈。。。最近也是准备好好在总结一下关于“埋点SDK”以及AOP的东西,会涉及到Runtime的知识点,这次可以认真带着自己的实践经验总结啦。。。最后给“脉脉”洗个澡,因为,我又回来了!
iOS RunTime你知道了总得用一下的更多相关文章
- ios runtime swizzle
ios runtime swizzle @implementation NSObject(Extension) + (void)swizzleClassMethod:(Class)class orig ...
- ios runtime的相关知识
一.iOS runtime原理 对于runtime机制,在网上找到的资料大概就是怎么去用这些东西,以及查看runtime.h头文件中的实现,当然这确实是一种很好的学习方法,但是,其实我们还是不会知道r ...
- iOS Runtime 实践(1)
很多时候我们都在看iOS开发中的黑魔法——Runtime.懂很多,但如何实践却少有人提及.本文便是iOS Runtime的实践第一篇. WebView 我们这次的实践主题,是使用针对接口编程的方式,借 ...
- 包建强的培训课程(11):iOS Runtime实战
@import url(http://i.cnblogs.com/Load.ashx?type=style&file=SyntaxHighlighter.css);@import url(/c ...
- iOS Runtime的消息转发机制
前面我们已经讲解Runtime的基本概念和基本使用,如果大家对Runtime机制不是很了解,可以先看一下以前的博客,会对理解这篇博客有所帮助!!! Runtime基本概念:https://www.cn ...
- iOS Runtime 实操练习
iOS Runtime 知识详解: http://yulingtianxia.com/blog/2014/11/05/objective-c-runtime/ 一般可以运行Runtime进行以下操作 ...
- iOS runtime探究(二): 从runtime開始深入理解OC消息转发机制
你要知道的runtime都在这里 转载请注明出处 http://blog.csdn.net/u014205968/article/details/67639289 本文主要解说runtime相关知识, ...
- IOS runtime动态运行时二
在C#.Java中有编译时多态和运行时多态,在OC中,只有运行时的多态,这与它的运行机制有关.OC中,方法的调用是通过消息的传递来进行的.在IOS runtime动态运行时一http://www.cn ...
- iOS --runtime理解
iOS~runtime理解 Runtime是想要做好iOS开发,或者说是真正的深刻的掌握OC这门语言所必需理解的东西.最近在学习Runtime,有自己的一些心得,整理如下,一为 查阅方便二为 或许能给 ...
随机推荐
- 7、手把手教你Extjs5(七)自定义菜单1
顶部和底部区域已经作好,在顶部区域有一个菜单的按钮,这一节我们设计一个菜单的数据结构,使其可以展示出不同样式的菜单.由于准备搭建的是一个系统模块自定义的系统,因此菜单也是自定义的,在操作员系统登录的时 ...
- js去除字符串空格
str.replace(/\s+/g,""); str.replace(/\s|\xA0/g,""); empName=empName.replace(/^\s ...
- 为什么无线信号(RSSI)是负值(转)
源:为什么无线信号(RSSI)是负值 为什么无线信号(RSSI)是负值 答:其实归根到底为什么接收的无线信号是负值,这样子是不是容易理解多了.因为无线信号多为mW级别,所以对它进行了极化,转化为dBm ...
- PHP文件夹操作2
mkdir("路径文件名"); 创建文件夹 imdir("路径文件名"); 删除文件夹(只能删除空的文件夹) rename("路径",&qu ...
- STM32的时钟树深入详解以及RCC配置
在STM32上如果不使用外部晶振,OSC_IN和OSC_OUT的接法 如果使用内部RC振荡器而不使用外部晶振,请按照下面方法处理: 1)对于100脚或144脚的产品,OSC_IN应接地,OSC_OUT ...
- PHP的高并发和大数据处理
收集前人的经验.加速学习,解决工作中的难题. 一.代码优化(包括sql语句的优化), 合理的使用索引,避免整表查询.二.日常海量数据处理我用文件缓存,文件缓存分两种,第一种是最常见的生成html静太文 ...
- apue- chapter 1 UNIX基础知识
1.C++实现ls命令 #include<dirent.h> #include<stdlib.h> #include<iostream> #include &quo ...
- 主成分分析PCA(转载)
主成分分析PCA 降维的必要性 1.多重共线性--预测变量之间相互关联.多重共线性会导致解空间的不稳定,从而可能导致结果的不连贯. 2.高维空间本身具有稀疏性.一维正态分布有68%的值落于正负标准差之 ...
- Antx简介(ali_PPT)
Antx的由来: §最早,我们用Makefile来build系统 •Makefile不适合Java的编译 §后来,我们用Ant来build系统 •开始时很不错 •随着项目增多,出现困难 §利用bean ...
- mysql 常用技巧
1.正则使用 比 LIKE 会牺牲很多的系统资源 尽量不要用 正则的语法和JS PHP 差不多 select * from t1 where email REGEXP "@163[,.]co ...