说点题外话:
我刚来现在这家公司的时候,老板让我下载一个脉脉,上去找找自己的同行,多认识些同行。其实初衷的好的,但最近这两天我把它卸载了,不为别的,负能量太多!iOS这行自从2016就没景气过,在这行混,这些自己也肯定都知道。但就是受不鸟铺天盖地的多久没找到工作,满大街都是iOS程序猿这些话题。看了也给我带不来任何的作用,你唯一能做的就是安安静静的做好自己该做的。自己入iOS这行也一年半过了,除去培训的那个几个月,真正摸爬滚打也一年多了,有时候想想,其实也没觉得有多差,以后怎样不知道,但至少现在,你有份工作,有口饭吃,还有时间给你去学习,有什么不知足的呢?在我自己浅薄的意识里,编程思想都是相同的,喜欢iOS你也可能也会喜欢安卓,Java,JS,PHP等等等。。活到老,学到老,那颗不停的去学的心就是自己最大的依靠。
回归正题:
以前有了解过Runtime,不记得是几个月前的事情了,最近又遇到这个问题,还是总结一下吧,总结的不好的地方,见谅了。。
Runtime俗称“运行时”,项目都有分一个编译和运行两个状态,这个应该了解。是一套底层的C语言的API。OC是一门动态的语言,有些东西不会放在我们编译的时候去处理,会等到运行时去处理。下面说的这些,建议大家随表这个项目,导入下面头文件点进去我们一起慢慢探讨!
#import
看看他最上面:
/// 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/** * 定义一个测试的协议 */@protocol protocolTestDelegate @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
还有许多:
其实细说这块的只是还有很多,像方法交换 、动态添加方法 、拦截调用等等等,但这个不能乱吹,我项目中暂时也没用过,以后可能会用到吧,现在有导航栏渐变这样的效果,把代码给出来!
给UINavigationBar添加一个类别:
#import#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的知识点,这次可以认真带着自己的实践经验总结啦。。。最后给“脉脉”洗个澡,因为,我又回来了!