iOS RunTime你知道了总得用一下

说点题外话:

      我刚来现在这家公司的时候,老板让我下载一个脉脉,上去找找自己的同行,多认识些同行。其实初衷的好的,但最近这两天我把它卸载了,不为别的,负能量太多!iOS这行自从2016就没景气过,在这行混,这些自己也肯定都知道。但就是受不鸟铺天盖地的多久没找到工作,满大街都是iOS程序猿这些话题。看了也给我带不来任何的作用,你唯一能做的就是安安静静的做好自己该做的。自己入iOS这行也一年半过了,除去培训的那个几个月,真正摸爬滚打也一年多了,有时候想想,其实也没觉得有多差,以后怎样不知道,但至少现在,你有份工作,有口饭吃,还有时间给你去学习,有什么不知足的呢?在我自己浅薄的意识里,编程思想都是相同的,喜欢iOS你也可能也会喜欢安卓,Java,JS,PHP等等等。。活到老,学到老,那颗不停的去学的心就是自己最大的依靠。

 

回归正题:


     以前有了解过Runtime,不记得是几个月前的事情了,最近又遇到这个问题,还是总结一下吧,总结的不好的地方,见谅了。。

      Runtime俗称“运行时”,项目都有分一个编译和运行两个状态,这个应该了解。是一套底层的C语言的API。OC是一门动态的语言,有些东西不会放在我们编译的时候去处理,会等到运行时去处理。下面说的这些,建议大家随表这个项目,导入下面头文件点进去我们一起慢慢探讨!

1
#import <objc/runtime.h>

看看他最上面:

1
2
3
4
5
6
7
8
9
10
11
/// 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; // 属性

定义在上面代码的注释里我们说了,再往下看你就看到的是类的表示:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
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 遵守的协议。

下面就是一系列的方法了,这里总结常见的,在下面的代码注释里面会说的比较详细点:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
#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;
<br>    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添加一个类别:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
#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 的代理方法里面:

1
2
3
4
5
6
- (void)scrollViewDidScroll:(UIScrollView *)scrollView
 {
 // 本质是让导航栏添加的BackgroundView属性根据你的scrollView的滑动范围改变颜色
 [self.navigationController.navigationBar NASetBackgroundColor:[color colorWithAlphaComponent:alpha]];
  
 }

这是在网上看到的一个效果,就是这种导航栏的渐变:

 

 

 

2018年3月30日


 

      翻到这篇以前的博客文章,是16年的了,现在看两年前的东西可能会稍微有点年代感,总结的也是自己刚在慢慢理解Runtime这个东西的时候写的,哈哈哈,虽然内容现在看值一毛钱,但好处是就像最开始时候说的那样从未停止过脚步,哈哈哈。。。最近也是准备好好在总结一下关于“埋点SDK”以及AOP的东西,会涉及到Runtime的知识点,这次可以认真带着自己的实践经验总结啦。。。最后给“脉脉”洗个澡,因为,我又回来了!

 

posted @   MrRisingSun  阅读(1132)  评论(0编辑  收藏  举报
编辑推荐:
· Java 中堆内存和栈内存上的数据分布和特点
· 开发中对象命名的一点思考
· .NET Core内存结构体系(Windows环境)底层原理浅谈
· C# 深度学习:对抗生成网络(GAN)训练头像生成模型
· .NET 适配 HarmonyOS 进展
阅读排行:
· 如何给本地部署的DeepSeek投喂数据,让他更懂你
· 超详细,DeepSeek 接入PyCharm实现AI编程!(支持本地部署DeepSeek及官方Dee
· 用 DeepSeek 给对象做个网站,她一定感动坏了
· .NET 8.0 + Linux 香橙派,实现高效的 IoT 数据采集与控制解决方案
· .NET中 泛型 + 依赖注入 的实现与应用
点击右上角即可分享
微信分享提示