当我在写千字文的时候我在写神马,类与对象
分类:技术

Objective-C语言是一门动态语言,它将很多静态语言在编译和链接时期做的事放到了运行时来处理。这种动态语言的优势在于:我们写代码时更具灵活性,如我们可以把消息转发给我们想要的对象,或者随意交换一个方法的实现等。

没有牛逼的资源帝,只有勤劳的搬运工

从语言学角度说这个题目有点不通呐,不过目前当红企业家、作家的代表作:春风十里不如你,个人也私下以为不通一样,话说春风十里具体所指为何,春风吹拂的十里苏堤还是十里垃圾场,春风十里这种适合做成动图的东东和人放一起类比合适吗。

这种特性意味着Objective-C不仅需要一个编译器,还需要一个运行时系统来执行编译的代码。对于Objective-C来说,这个运行时系统就像一个操作系统一样:它让所有的工作可以正常的运行。这个运行时系统即Objc RuntimeObjc Runtime其实是一个Runtime库,它基本上是用C和汇编写的,这个库使得C语言有了面向对象的能力。

首先要声明一点,独立鱼电影不会推荐PT站或者其他需要邀请注册的网站,本文提到的一定都是无需注册或者开放注册的、简单实用的网站。

当然我们也可以扯虎皮的说一句,随着汉语的不断西化、欧化、网络化,这种看似不通的语句才是主旋律呐,所以俺这个也算是攀鳞附翼了吧。好了,吐槽完毕,开说主题。其实严格说一直以来吐槽---就是俺的基本风格,写了9个月了从未变过。个人每天写的所谓文文,基本都是给口水文一词做注解的。但身为一个话痨,能喷,是俺在生活中的一天特点,由口说延展到写作,就形成了多彩多姿,题材各异的写作风格。(众:你还能更不要脸一点吗?俺:当然,不信接着往下看呐)于是借助简书文集功能的梳理,俺惊诧的发现到现在俺居然有13个文集了,真是好吉利的数字喔。当然这个数字还会进一步增加的,不是迷信,而是虽然已经设置了13个文集了,但现在有的文章还是有不知道往那里搁的苦恼呢。总体而言,开展此项活动近一年来,个人在个人的“试着写写看,写到那算哪”精神的引领下,在个人肉体与灵魂的积极努力下,在社会各方的帮助支持下(感谢单位的电脑、办公室、办公桌、水、电、厕所、员工餐厅、感谢领导赐给俺一份稳定的工作,不但给俺发工资,还给上五险一金呢,感动的泪奔个),在胡扯闲聊上取得了巨大进展,现将个人工作、文集列表总结如下:

Runtime库主要做下面几件事:

1、封装:在这个库中,对象可以用C语言中的结构体表示,而方法可以用C函数来实现,另外再加上了一些额外的特性。这些结构体和函数被runtime函数封装后,我们就可以在程序运行时创建,检查,修改类、对象和它们的方法了。
2、找出方法的最终执行代码:当程序执行[object doSomething]时,会向消息接收者(object)发送一条消息(doSomething),runtime会根据消息接收者是否能响应该消息而做出不同的反应。这将在后面详细介绍。

Objective-C runtime目前有两个版本:Modern runtimeLegacy runtimeModern Runtime覆盖了64位的Mac OS X Apps,还有iOS AppsLegacy Runtime是早期用来给32位 Mac OS X Apps 用的,也就是可以不用管就是了。

在这一系列文章中,我们将介绍runtime的基本工作原理,以及如何利用它让我们的程序变得更加灵活。在本文中,我们先来介绍一下类与对象,这是面向对象的基础,我们看看在Runtime中,类是如何实现的。

如果你不是那么热爱电影,只是闲暇之余看看热门的新片/美剧,不求画质与速度的话,那么下面这几个网站已经能满足你了:

我的文集(都是吐槽,只是吐的内容各异罢了):

类与对象基础数据结构

入门级

电商、市场、所思所想:这个真的都是吐槽,都是吐槽,都是吐槽。做为一个资深网购党、生活观察家(也不知道谁发明出这样装*的职衔来的)

Class

Objective-C类是由Class类型来表示的,它实际上是一个指向objc_class结构体的指针。它的定义如下:

1  typedef struct objc_class *Class;

查看objc/runtime.hobjc_class结构体的定义如下:

1  struct objc_class {
2
3      Class isa  OBJC_ISA_AVAILABILITY;
4
5   #if !__OBJC2__
6      Class super_class                       OBJC2_UNAVAILABLE;   // 父类
7      const char *name                         OBJC2_UNAVAILABLE;  // 类名
8      long version                             OBJC2_UNAVAILABLE;  // 类的版本信息,默认为0
9      long info                                OBJC2_UNAVAILABLE;  // 类信息,供运行期使用的一些位标识
10     long instance_size                       OBJC2_UNAVAILABLE;  // 该类的实例变量大小
11     struct objc_ivar_list *ivars             OBJC2_UNAVAILABLE;  // 该类的成员变量链表
12     struct objc_method_list **methodLists    OBJC2_UNAVAILABLE;  // 方法定义的链表
13     struct objc_cache *cache                 OBJC2_UNAVAILABLE;  // 方法缓存
14     struct objc_protocol_list *protocols     OBJC2_UNAVAILABLE;  // 协议链表
15
16  #endif
17  } OBJC2_UNAVAILABLE;

在这个定义中,下面几个字段是我们感兴趣的

isa:需要注意的是在Objective-C中,所有的类自身也是一个对象,这个对象的Class里面也有一个isa指针,它指向metaClass(元类),我们会在后面介绍它。
super_class:指向该类的父类,如果该类已经是最顶层的根类(如NSObjectNSProxy),则super_class为NULL。
cache:用于缓存最近使用的方法。一个接收者对象接收到一个消息时,它会根据isa指针去查找能够响应这个消息的对象。在实际使用中,这个对象只有一部分方法是常用的,很多方法其实很少用或者根本用不上。这种情况下,如果每次消息来时,我们都是methodLists中遍历一遍,性能势必很差。这时,cache就派上用场了。在我们每次调用过一个方法后,这个方法就会被缓存到cache列表中,下次调用的时候runtime就会优先去cache中查找,如果cache没有,才去methodLists中查找方法。这样,对于那些经常用到的方法的调用,但提高了调用的效率。
version:我们可以使用这个字段来提供类的版本信息。这对于对象的序列化非常有用,它可是让我们识别出不同类定义版本中实例变量布局的改变。
针对cache,我们用下面例子来说明其执行过程:

1   NSArray *array = [[NSArray alloc] init];
2   其流程是:
3   1. `[NSArray alloc]`先被执行。因为NSArray没有`+alloc`方法,于是去父类NSObject去查找。
4   2. 检测NSObject是否响应`+alloc`方法,发现响应,于是检测NSArray类,并根据其所需的内存空间大小开始分配内存空间,然后把`isa`指针指向NSArray类。同时,`+alloc`也被加进cache列表里面。
5   3. 接着,执行`-init`方法,如果NSArray响应该方法,则直接将其加入`cache`;如果不响应,则去父类查找。
6   4. 在后期的操作中,如果再以`[[NSArray alloc] init]`这种方式来创建数组,则会直接从cache中取出相应的方法,直接调用。
7   ### objc_object与id
8   `objc_object`是表示一个类的实例的结构体,它的定义如下(`objc/objc.h`):
9    objc
10   struct objc_object {
11       Class isa  OBJC_ISA_AVAILABILITY;
12   };
13
14   typedef struct objc_object *id;

可以看到,这个结构体只有一个字体,即指向其类的isa指针。这样,当我们向一个Objective-C对象发送消息时,运行时库会根据实例对象的isa指针找到这个实例对象所属的类。Runtime库会在类的方法列表及父类的方法列表中去寻找与消息对应的selector指向的方法。找到后即运行这个方法。

当创建一个特定类的实例对象时,分配的内存包含一个objc_object数据结构,然后是类的实例变量的数据。NSObject类的allocallocWithZone:方法使用函数class_createInstance来创建objc_object数据结构。

另外还有我们常见的id,它是一个objc_object结构类型的指针。它的存在可以让我们实现类似于C++中泛型的一些操作。该类型的对象可以转换为任何一种对象,有点类似于C语言中void *指针类型的作用。

电影天堂:http://www.xiaopian.com/

,把生活中那些有关社会变迁、时代发展、电商进步的事例记下来也是应有之意了。其实文章里面的事情很多人预计大多都遇见过,只不过专门记下来还要加以解说估计也就只有话痨如我这般的观察家才会来得。比如微信支付,比如个人信息被无良商家拿去刷单,比如实体店与生鲜电商,个人自以为都是薅住时代脖领子的好文章咧,当然更有可能的是只有个人是这么认为的。

objc_cache

上面提到了objc_class结构体中的cache字段,它用于缓存调用过的方法。这个字段是一个指向objc_cache结构体的指针,其定义如下:

1   struct objc_cache {
2
3       unsigned int mask /* total = mask + 1 */                 OBJC2_UNAVAILABLE;
4       unsigned int occupied                                    OBJC2_UNAVAILABLE;
5       Method buckets[1]                                        OBJC2_UNAVAILABLE;
6
7   }; 

该结构体的字段描述如下:

mask:一个整数,指定分配的缓存bucket的总数。在方法查找过程中,Objective-C runtime使用这个字段来确定开始线性查找数组的索引位置。指向方法selector的指针与该字段做一个AND位操作(index = (mask & selector))。这可以作为一个简单的hash散列算法。
occupied:一个整数,指定实际占用的缓存bucket的总数。
buckets:指向Method数据结构指针的数组。这个数组可能包含不超过mask+1个元素。需要注意的是,指针可能是NULL,表示这个缓存bucket没有被占用,另外被占用的bucket可能是不连续的。这个数组可能会随着时间而增长。

飘花电影:http://www.piaohua.com/

勉强与工作有关的东东:不得不承认俺个人的工作真的没啥可说的,工作清淡如水的报社没嘛宫斗宅斗神马的,大家都平凡的生活着,虽然不是人人进取,个个争先的为实现中国梦做出积极贡献吧,但之于社会的和谐稳定而言,俺们这伙子俗人绝对是个中主干。但是为毛俺还会写出一堆所谓的职场文呐,因为俺是女生啊,一个女生不八卦真是没天理啊,更表说身为一只社会动物,她周围有同学、前同事、闺蜜、好姐妹这些生物呐,这些所谓职场女性所处单位机关、国企、私企、外企一应俱全,这如同无产阶级除了锁链没有什么可以失去的,一群女生坐在一起除了八卦更没啥可干啊,每个人讲个段子就够写上几天了好吗?这里面有机关深化改革、新老同事间各种撕逼宫心计、各凭手段升职记、中国制造业之困等等各种看似高大上的主题,俺本着身为一名八卦记录者、社会书记员的原则,坚持像那些三流网站一样,不生产内容,只做内容的搬运工。终日提着个酱油瓶,在一旁像老子(有分析说老子不光担任过国立图书馆馆长喔,还长期从事过朝堂上的会议记录工作,每天亲见各种撕*大战咳,总结出来的东西能不深刻么)一样默默的记录着。虽然题材精彩万千,八卦内容不断,但最终成文的,正如高晓松每期节目片头所说:历史不是镜子,历史是精子,牺牲亿万才有一个实体出现。个人一贯秉承去粗存精的精神,不搞笑的,不具深刻参考、反思意义的,容易被人肉出事件主人公的,内容三俗的,咳,不得不说新时代各种**关系的互动真是只有你想不到的,没人家做不出的,无数次吓到宝宝呢,如果对各种潜规则,各种乱搞男女关系,搞乱男女关系的职场事件进行记录,那么这个专栏的东东起码能再多十几篇,悲剧的是基本这些故事的结局都是大团圆,升官的升官,发财的发财,升官发财的升官发财。针对这些东东,个人本着羡慕嫉妒恨的原则一律不予记录,俺这个行文风格绝对要像《阅微草堂笔记》一样,劝善惩恶,藿香正气。(宣宣在一边挥舞着皮鞭,说多少遍了,让你们弘扬正能量,续写社会主义新篇章,你上面写这些都是什么鬼。俺立即五体俯地,大人我错了,小的马上改去。)

元类(Meta Class)

在上面我们提到,所有的类自身也是一个对象,我们可以向这个对象发送消息(即调用类方法)。如:

1   NSArray *array = [NSArray array];

这个例子中,+array消息发送给了NSArray类,而这个NSArray也是一个对象。既然是对象,那么它也是一个objc_object指针,它包含一个指向其类的一个isa指针。那么这些就有一个问题了,这个isa指针指向什么呢?为了调用+array方法,这个类的isa指针必须指向一个包含这些类方法的一个objc_class结构体。这就引出了meta-class的概念

    meta-class是一个类对象的类。

当我们向一个对象发送消息时,runtime会在这个对象所属的这个类的方法列表中查找方法;而向一个类发送消息时,会在这个类的meta-class的方法列表中查找。

meta-class之所以重要,是因为它存储着一个类的所有类方法。每个类都会有一个单独的meta-class,因为每个类的类方法基本不可能完全相同。

再深入一下,meta-class也是一个类,也可以向它发送一个消息,那么它的isa又是指向什么呢?为了不让这种结构无限延伸下去,Objective-C的设计者让所有的meta-class的isa指向基类的meta-class,以此作为它们的所属类。即,任何NSObject继承体系下的meta-class都使用NSObject的meta-class作为自己的所属类,而基类的meta-class的isa指针是指向它自己。这样就形成了一个完美的闭环。

通过上面的描述,再加上对objc_class结构体中super_class指针的分析,我们就可以描绘出类及相应meta-class类的一个继承体系了

对于NSObject继承体系来说,其实例方法对体系中的所有实例、类和meta-class都是有效的;而类方法对于体系内的所有类和meta-class都是有效的。

讲了这么多,我们还是来写个例子吧:

void TestMetaClass(id self, SEL _cmd) {

    NSLog(@"This objcet is %p", self);
    NSLog(@"Class is %@, super class is %@", [self class], [self superclass]);

    Class currentClass = [self class];
    for (int i = 0; i < 4; i++) {
        NSLog(@"Following the isa pointer %d times gives %p", i, currentClass);
        currentClass = objc_getClass((__bridge void *)currentClass);
    }

    NSLog(@"NSObject's class is %p", [NSObject class]);
    NSLog(@"NSObject's meta class is %p", objc_getClass((__bridge void *)[NSObject class]));
}

#pragma mark -
@implementation Test

- (void)ex_registerClassPair {

    Class newClass = objc_allocateClassPair([NSError class], "TestClass", 0);
    class_addMethod(newClass, @selector(testMetaClass), (IMP)TestMetaClass, "v@:");
    objc_registerClassPair(newClass);

    id instance = [[newClass alloc] initWithDomain:@"some domain" code:0 userInfo:nil];
    [instance performSelector:@selector(testMetaClass)];
}

@end

这个例子是在运行时创建了一个NSError的子类TestClass,然后为这个子类添加一个方法testMetaClass,这个方法的实现是TestMetaClass函数。

运行后,打印结果是

2014-10-20 22:57:07.352 mountain[1303:41490] This objcet is 0x7a6e22b0
2014-10-20 22:57:07.353 mountain[1303:41490] Class is TestStringClass, super class is NSError
2014-10-20 22:57:07.353 mountain[1303:41490] Following the isa pointer 0 times gives 0x7a6e21b0
2014-10-20 22:57:07.353 mountain[1303:41490] Following the isa pointer 1 times gives 0x0
2014-10-20 22:57:07.353 mountain[1303:41490] Following the isa pointer 2 times gives 0x0
2014-10-20 22:57:07.353 mountain[1303:41490] Following the isa pointer 3 times gives 0x0
2014-10-20 22:57:07.353 mountain[1303:41490] NSObject's class is 0xe10000
2014-10-20 22:57:07.354 mountain[1303:41490] NSObject's meta class is 0x0

我们在for循环中,我们通过objc_getClass来获取对象的isa,并将其打印出来,依此一直回溯到NSObjectmeta-class。分析打印结果,可以看到最后指针指向的地址是0x0,即NSObjectmeta-class的类地址。

这里需要注意的是:我们在一个类对象调用class方法是无法获取meta-class,它只是返回类而已。

6V电影:http://www.6vdy.com/

21日养成记录:这个纯粹是写给自己看的,以这九个月来自己将自己当小白鼠的经历而言,俺是忠诚的贯彻了“21天养成习惯”的培养精神的,每21天为一个周期,自我总结,顺便催眠下自己有神马自我提高,同时又找到借口给自己买份礼物。话说定期奖励自己真是个好习惯呐,一百遍,俺初期有好几次就是靠这个自己哄自己,自己骗自己,才能写下去的。等到你写过N个21天之后,心理学、社会学、生理学、人体力学等等等等理论加实践证明,写文已经成为你生活中的一部分,就和每天都要吃早餐一样,不存在神马要专门为其腾出时间、精力,已经和呼吸一样自然袅。

类与对象操作函数

runtime提供了大量的函数来操作类与对象。类的操作方法大部分是以class_为前缀的,而对象的操作方法大部分是以objc_或object_为前缀。下面我们将根据这些方法的用途来分类讨论这些方法的使用。

圣城家园:http://www.cnscg.org/

假装在读书:虽然在日常工作生活中有个“爱看书”的假名声,但比起真正的读书者来说,真是笑死宝宝了。所以个人的读书心得自称做“闲书笔记”,个人看闲书之余有啥碎念杂想不好归类的,便统统放进这只筐,只要有关看书这事的,啥都能装。

类相关操作函数

我们可以回过头去看看objc_class
的定义,runtime提供的操作类的方法主要就是针对这个结构体中的各个字段的。下面我们分别介绍这一些的函数。并在最后以实例来演示这些函数的具体用法。

电影FM:http://dianying.fm/category/

闲书笔记:这个专栏应该是目前文章数量最多的,没有之一了。咳咳,你看居然有72篇之多,为毛呢,因为大家都知道,改革需要大胆的试,大胆的闯,可大干一场之前怎么少的了画上一个圈,开出一块试验田。这个便是改革的浅水区,示范基地。话说,话说,刚刚开始写文的时候,俺是不知道写神马好的,于是便从最熟的领域开刀,写读书笔记便好,就酱紫俺就像一个初习做饭只会用电饭煲焖米饭的小学生一样,每日只是写着各种读书笔记。其中还有很多书是从前看过的,因为如果你要搞什么日读一书日写一文之类的日更法则,那么最容易也最可能会实现的就是看快书(垃圾书、畅销书、轻薄书)写快文(吐槽神马的俺最在行了,事实上,批评一本滥书比总结一本好书好写的多多多多多多了。)

类名(name)

类名操作的函数主要有:

1  // 获取类的类名
2  const char * class_getName ( Class cls );

对于class_getName函数,如果传入的cls为Nil,则返回一个字字符串。

人人影视(需注册):http://www.yyets.com/(目前中国站已经关闭,但推出了海外站。最强大的除了美剧资源,HR-HDTV格式的片源也是人人影视的一大特色,体积小,一般是2G左右,但是画质不错,甚至在电视上播放也不会让你失望)

那些有关中国制造的吐槽:这个专题么,这个专题真是,咳咳,万幸最近没什么更新了,话说打从俺完成了每天写篇读书笔记到每天写篇文的转变后,什么身边事、心中想统统都写上,于是情人节和好姐妹聚会看到大街上一堆一堆的年轻人卖一堆一堆的廉价玫瑰,来一发。春节发现放鞭炮的人少了也要来一发,各种自说自话,简直有如经济学家们拿着女人的裙长、口红销量分析经济景气指数一样,极不要脸的说,俺这个也是YY着以一叶落断天下寒,以小笔管窥世间万千。可是事实是世界精彩万千,天天更新无限,什么时候打开社会新闻版都惊见狗血一片,现实永远比各种影视剧热闹,每天都有各种万万想不到,所以俺不是社会的书记员,俺这个只是庶民的家用账而已罢了。

父类(super_class)和元类(meta-class)

父类和元类操作的函数主要有:

1   // 获取类的父类
2   Class class_getSuperclass ( Class cls );
3
4  // 判断给定的Class是否是一个元类
5   BOOL class_isMetaClass ( Class cls );
  • 1、class_getSuperclass函数,当cls为Nil或者cls为根类时,返回Nil。不过通常我们可以使用NSObject类的superclass方法来达到同样的目的。
  • 2、class_isMetaClass函数,如果是cls是元类,则返回YES;如果否或者传入的cls为Nil,则返回NO。

这几个简单好用,但是很多新片都有重复的,基本上掌握一两个就够用了。

战国杂录:这个,咳咳,这个的确是新开辟的,无他,其中收录内容实在找不到那个专栏可以收录了。所以只好在已经有很多专栏的情况下再添一家。这个所谓专栏的产生完全是一种过激反应,做为一个比较感性的小女生,实在是抗不住日复一日的抗日神剧和抗战教育了,好在视频网站足够给力,于是《转动历史的时刻》就成了每天的观看主题。虽然栏中小文都是个人所思所感,级别往大了说也就是个沟渠,河伯见汪洋而兴叹,俺这个看看玉渊潭的照片就要拜伏于地了,好在万幸俺写的东东没啥人看,不至遗害太远。

实例变量大小(instance_size)

实例变量大小操作的函数有:

1   // 获取实例大小
2   size_t class_getInstanceSize ( Class cls );

如果你有以下任一需求:1、爱看经典老电影,2、爱看高清画质的电影,3、想尽快拿到新片资源。最好学会用这些网站:

声、光、电、影、视、片:这个名字起的很热闹是吧,因为内容就很热闹哪,范围广,时间长,各种电影、电视剧、纪录片、声光电的东东,都在这里面,没办法,因为俺看的东东杂啊,杂家入宫这么多年,咳,不,是看了那么多电影、纪录片,总如吃烤翅一般有很多鸡骨不吐不快啊。更何况本着要对自己狠一点儿的创作精神,俺对自身写作内容的要求可是全面发展,看过什么电影、电视剧,怎么也得写篇观后感神马的才算看过不是,不然过些时日便全然忘却的可能性是很大很大的喔,写在这里也记到一种记录下来的效果。

成员变量(ivars)及属性

在objc_class中,所有的成员变量、属性的信息是放在链表ivars中的。ivars是一个数组,数组中每个元素是指向Ivar(变量信息)的指针。runtime提供了丰富的函数来操作这一字段。大体上可以分为以下几类:

1.成员变量操作函数,主要包含以下函数:

1   // 获取类中指定名称实例成员变量的信息
2   Ivar class_getInstanceVariable ( Class cls, const char *name );
3
4   // 获取类成员变量的信息
5   Ivar class_getClassVariable ( Class cls, const char *name );
6   
7   // 添加成员变量
8   BOOL class_addIvar ( Class cls, const char *name, size_t size, uint8_t alignment, const char *types );
9
10   // 获取整个成员变量列表
11   Ivar * class_copyIvarList ( Class cls, unsigned int *outCount );
  • class_getInstanceVariable函数,它返回一个指向包含name指定的成员变量信息的objc_ivar结构体的指针(Ivar)。

  • class_getClassVariable函数,目前没有找到关于Objective-C中类变量的信息,一般认为Objective-C不支持类变量。注意,返回的列表不包含父类的成员变量和属性。

  • Objective-C不支持往已存在的类中添加实例变量,因此不管是系统库提供的提供的类,还是我们自定义的类,都无法动态添加成员变量。但如果我们通过运行时来创建一个类的话,又应该如何给它添加成员变量呢?这时我们就可以使用class_addIvar函数了。不过需要注意的是,这个方法只能在objc_allocateClassPair函数与objc_registerClassPair之间调用。另外,这个类也不能是元类。成员变量的按字节最小对齐量是1<<alignment。这取决于ivar的类型和机器的架构。如果变量的类型是指针类型,则传递log2(sizeof(pointer_type))。

  • class_copyIvarList函数,它返回一个指向成员变量信息的数组,数组中每个元素是指向该成员变量信息的objc_ivar结构体的指针。这个数组不包含在父类中声明的变量。outCount指针返回数组的大小。需要注意的是,我们必须使用free()来释放这个数组。

2.属性操作函数,主要包含以下函数:

1    // 获取指定的属性
2    objc_property_t class_getProperty ( Class cls, const char *name );
3
4    // 获取属性列表
5    objc_property_t * class_copyPropertyList ( Class cls, unsigned int *outCount );
6
7    // 为类添加属性
8    BOOL class_addProperty ( Class cls, const char *name, const objc_property_attribute_t *attributes, unsigned int attributeCount );
9
10   // 替换类的属性
11   void class_replaceProperty ( Class cls, const char *name, const objc_property_attribute_t *attributes, unsigned int attributeCount );

这一种方法也是针对ivars来操作,不过只操作那些是属性的值。我们在后面介绍属性时会再遇到这些函数。

3.在MAC OS X系统中,我们可以使用垃圾回收器。runtime提供了几个函数来确定一个对象的内存区域是否可以被垃圾回收器扫描,以处理strong/weak引用。这几个函数定义如下:

1   const uint8_t * class_getIvarLayout ( Class cls );
2   void class_setIvarLayout ( Class cls, const uint8_t *layout );
3   const uint8_t * class_getWeakIvarLayout ( Class cls );
4   void class_setWeakIvarLayout ( Class cls, const uint8_t *layout );

但通常情况下,我们不需要去主动调用这些方法;在调用objc_registerClassPair时,会生成合理的布局。在此不详细介绍这些函数。

爱好级

有时读书系列:这个真的是,最奇葩的专栏了,没有之一,是的。这个有时读书,个人目前还没有见到其它读书人总结过。总之概括下就是在各种极品、极端、变态或不极品、不极端、不变态的条件下的读书经过,以及各种情境下适合读神马的个人心得总结。目前还有好几篇没来的及写的,欠账好多,先放几篇成品作的题目你们感受下,那酸爽。实地考察排队的时候读什么书实事求是实地实践洗衣服的时候看什么书略谈工作的时候看什么书略谈写博客的时候听什么书---唐诗三百首2.14之忙的一日总结兼论略谈唱KTV的时候读什么书略谈与人聊天的时候读什么书---日本人编的中国书法字典?!

方法(methodLists)

方法操作主要有以下函数:

1   // 添加方法
2   BOOL class_addMethod ( Class cls, SEL name, IMP imp, const char *types );
3   // 获取实例方法
4   Method class_getInstanceMethod ( Class cls, SEL name );
5   // 获取类方法
6   Method class_getClassMethod ( Class cls, SEL name );
7   // 获取所有方法的数组
8   Method * class_copyMethodList ( Class cls, unsigned int *outCount );
9   // 替代方法的实现
10  IMP class_replaceMethod ( Class cls, SEL name, IMP imp, const char *types );
11  // 返回方法的具体实现
12  IMP class_getMethodImplementation ( Class cls, SEL name );
13  IMP class_getMethodImplementation_stret ( Class cls, SEL name );
14  // 类实例是否响应指定的selector
15  BOOL class_respondsToSelector ( Class cls, SEL sel );

ED2000:http://www.ed2000.com/(网站提供的都是电驴链接,电影资源很强大,游戏/音乐/软件什么乱七八糟的都有)

生活记录塈段子元素:到现在为止这个专栏真是文章第二多的所在咳,目前有55篇,而且会不断发展,预计未来便如印度人口总数超越我国一般,成为文章总量第一大栏喽。无他,因为把日子过成段子一向是个人对生活的基本看法并始终实地积极践行之,所以这些记录下生活中诸般杂事的专栏也是日常各种段子的出处。把生活过成段子,在段子中生活,JUST DO IT。当然,做为一篇篇话痨写就的文章,吐槽自是必不可少。所以,在个人的不懈努力下,现在吐槽和段子已经基本合二为一袅。这也从另一凸显出写文章这事儿的一大特性,它能帮助你认清自己,虽然事实多数时候是以比较残忍的方式出现,比如说俺按鍵写文是在个人创作稿件被领导训教多次后为了提高自己的创作水平才来练笔的,但写来写去的结果就是发现自己根本不适合写那种浓浓党报范儿风格的宏篇大作,俺最擅长的,适合的,写着快手、顺手的,就是那种吐槽文呐,泪奔个,看来神马范长江、吴玉章一类的大奖是此生无望啊(众:同志,醒醒!来先把药吃了)。认清事实的残忍后还要面对严酷的现实,这是件多么令人悲伤的事。

- class_addMethod的实现会覆盖父类的方法实现,但不会取代本类中已存在的实现,如果本类中包含一个同名的实现,则函数会返回NO。如果要修改已存在实现,可以使用method_setImplementation。一个Objective-C方法是一个简单的C函数,它至少包含两个参数–self_cmd。所以,我们的实现函数(IMP参数指向的函数)至少需要两个参数,如下所示:

1   void myMethodIMP(id self, SEL _cmd)
2   {
3        // implementation ....
4   }

与成员变量不同的是,我们可以为类动态添加方法,不管这个类是否已存在。

另外,参数types是一个描述传递给方法的参数类型的字符数组,这就涉及到类型编码,我们将在后面介绍。

  • class_getInstanceMethodclass_getClassMethod函数,与class_copyMethodList不同的是,这两个函数都会去搜索父类的实现。

  • class_copyMethodList函数,返回包含所有实例方法的数组,如果需要获取类方法,则可以使用class_copyMethodList(object_getClass(cls), &count)(一个类的实例方法是定义在元类里面)。该列表不包含父类实现的方法。outCount参数返回方法的个数。在获取到列表后,我们需要使用free()方法来释放它。

  • class_replaceMethod函数,该函数的行为可以分为两种:如果类中不存在name指定的方法,则类似于class_addMethod函数一样会添加方法;如果类中已存在name指定的方法,则类似于method_setImplementation一样替代原方法的实现。

  • class_getMethodImplementation函数,该函数在向类实例发送消息时会被调用,并返回一个指向方法实现函数的指针。这个函数会比method_getImplementation(class_getInstanceMethod(cls, name))更快。返回的函数指针可能是一个指向runtime内部的函数,而不一定是方法的实际实现。例如,如果类实例无法响应selector,则返回的函数指针将是运行时消息转发机制的一部分。

  • class_respondsToSelector函数,我们通常使用NSObject类的respondsToSelector:instancesRespondToSelector:方法来达到相同目的。

SimpleCD:http://www.simplecd.me/(有电驴/种子/网盘等资源链接,很有名气的一个站)

闲思乱语碎碎念:这个么,心虚的呵呵下,这个算是生活记录塈段子元素的前身吧,开始各种生活中所思所感都是放这里面的,但后来发现这个名字远远不能承载内容之万一汗。比如说个人一向致力于将事件看成段子,将每天的文文写成段子,但这些段子文放在这个专题里就未免太不切题啦,于是,所以,舍旧立新才是应有之意,于是之后写的那些文文便都放在生活元素专栏里去了,当然,也有几篇纯属口水,非常切合闲思乱语主题的,便放在这里了,只不过从实事求是的角度说个人生活所经历的还是段子居多。

协议(objc_protocol_list)

协议相关的操作包含以下函数:

1   // 添加协议
2   BOOL class_addProtocol ( Class cls, Protocol *protocol );
3
4   // 返回类是否实现指定的协议
5   BOOL class_conformsToProtocol ( Class cls, Protocol *protocol );
6
7   // 返回类实现的协议列表
8   Protocol * class_copyProtocolList ( Class cls, unsigned int *outCount );
  • class_conformsToProtocol函数可以使用NSObject类的conformsToProtocol:方法来替代。

  • class_copyProtocolList函数返回的是一个数组,在使用后我们需要使用free()手动释放。

BT天堂:http://www.bttiantang.com/(片子很多,优点是对于热门电影来说,它提供了各大压制组/各版本的资源选择,BDRip/720p/1080p等等,另外可以通过IMDB编号来搜索影片)

万物生长绿意长:这个名字好诗意,做为有空就读全唐诗,至今阅读进度已达1%的人而言,真是用事实证明读诗真的有用,的确有用,非常有用。做为一个煞费苦心在阳台种菜的银,还是有很多失败经历可以记录下来,分享一下的。如果长久发展下去的话,可以发展成一个《论一百种种菜失败的方法》的专栏呐,不过好在还有好多好种耐活的东东,在给生活增添绿色的同时更向我展示了大自然的生灭法则,令人在种一盆盆小花的时候也在读一本本大书,有时还有所谓窥见天道的感悟。

版本(version)

版本相关的操作包含以下函数:

1   // 获取版本号
2   int class_getVersion ( Class cls );
3
4   // 设置版本号
5   void class_setVersion ( Class cls, int version );

BT之家:http://bbs.1lou.com/(综合性很强,在电影方面主要是中字熟肉,方便手机/iPad等移动设备观看)

食:圣人言大道至简,俺这个当然不是,因为馋,且敢想敢干,所以这两种精神体现在日常生活中就是什么材料都敢招呼,什么暗黑料理都敢做嚯,各种作各种做,各种吃吃喝喝,起个什么名字好呢,想一想统一属性都是往嘴里倒的,一字简之,名曰:食。虽然先前想过叫吃,可想想太俗了不是。于是为表吃意,命名曰“食”。所谓言有尽而意无穷是也,而且无论做神马东西放这里都不在话下。

其它

runtime还提供了两个函数来供CoreFoundation的tool-free bridging使用,即:

1   Class objc_getFutureClass ( const char *name );
2   void objc_setFutureClass ( Class cls, const char *name );

通常我们不直接使用这两个函数。

顶好精品论坛(需注册):http://bmdruchinyan.com/(重点推荐,影片分类很牛逼,比如著名导演的合集/TOP 250合集/三大电影节合集/CC标准收藏合集)

按照议论文的书写法则,该到了总结全篇的时候了,不过,还是有些废话要说:其实,写了这么多所谓的文章后当然会有一些问题出现的,譬如说吧:打了这许多字出来,卖废纸也能卖好几块,这么一大坨东东,放在家里也要占去不少空地不是。还有互联网时代的新问题,比如被同事家人看到这些肿么办?个人观点,以前是凉拌,现在天气冷了,直接上火锅,一锅涮。且不说俺们那些同事虽然都是党报员工,可那阅读欣赏水平都是《太阳报》的死忠粉儿那种。如果俺这个是发布各种职场八卦,各种那*和那&搞在一起啦,这种每天单位茶水间里喜闻乐见的话题,预计点击率早就分分钟狂飙突进,一准天天上首页的节奏。那会如此沉寂,更不必提按照大众传播的客观规律,一贯是越三俗越有话题,俺这些自认为小众的东西,如何做面包,怎样养花种菜云云,预计印成精装书向同事亲友分送也都要被拿去覆瓮,如果现下谁家还腌咸菜的话。

实例(Example)

上面列举了大量类操作的函数,下面我们写个实例,来看看这些函数的实例效果:

//-----------------------------------------------------------
// MyClass.h
@interface MyClass : NSObject <NSCopying, NSCoding>
@property (nonatomic, strong) NSArray *array;
@property (nonatomic, copy) NSString *string;
- (void)method1;
- (void)method2;
+ (void)classMethod1;
@end
//-----------------------------------------------------------
// MyClass.m
#import "MyClass.h"
@interface MyClass () {
    NSInteger       _instance1;
    NSString    *   _instance2;
}
@property (nonatomic, assign) NSUInteger integer;
- (void)method3WithArg1:(NSInteger)arg1 arg2:(NSString *)arg2;
@end
@implementation MyClass
+ (void)classMethod1 {
}
- (void)method1 {
    NSLog(@"call method method1");
}
- (void)method2 {
}
- (void)method3WithArg1:(NSInteger)arg1 arg2:(NSString *)arg2 {
    NSLog(@"arg1 : %ld, arg2 : %@", arg1, arg2);
}
@end
//-----------------------------------------------------------
// main.h
#import "MyClass.h"
#import "MySubClass.h"
#import <objc/runtime.h>
int main(int argc, const char * argv[]) {
    @autoreleasepool {

        MyClass *myClass = [[MyClass alloc] init];
        unsigned int outCount = 0;
        Class cls = myClass.class;
        // 类名
        NSLog(@"class name: %s", class_getName(cls));
        NSLog(@"==========================================================");
        // 父类
        NSLog(@"super class name: %s", class_getName(class_getSuperclass(cls)));
        NSLog(@"==========================================================");
        // 是否是元类
        NSLog(@"MyClass is %@ a meta-class", (class_isMetaClass(cls) ? @"" : @"not"));
        NSLog(@"==========================================================");
        Class meta_class = objc_getMetaClass(class_getName(cls));
        NSLog(@"%s's meta-class is %s", class_getName(cls), class_getName(meta_class));
        NSLog(@"==========================================================");
        // 变量实例大小
        NSLog(@"instance size: %zu", class_getInstanceSize(cls));
        NSLog(@"==========================================================");
        // 成员变量
        Ivar *ivars = class_copyIvarList(cls, &outCount);
        for (int i = 0; i < outCount; i++) {
            Ivar ivar = ivars[i];
            NSLog(@"instance variable's name: %s at index: %d", ivar_getName(ivar), i);
        }
        free(ivars);
        Ivar string = class_getInstanceVariable(cls, "_string");
        if (string != NULL) {
            NSLog(@"instace variable %s", ivar_getName(string));
        }
        NSLog(@"==========================================================");
        // 属性操作
        objc_property_t * properties = class_copyPropertyList(cls, &outCount);
        for (int i = 0; i < outCount; i++) {
            objc_property_t property = properties[i];
            NSLog(@"property's name: %s", property_getName(property));
        }
        free(properties);
        objc_property_t array = class_getProperty(cls, "array");
        if (array != NULL) {
            NSLog(@"property %s", property_getName(array));
        }
        NSLog(@"==========================================================");
        // 方法操作
        Method *methods = class_copyMethodList(cls, &outCount);
        for (int i = 0; i < outCount; i++) {
            Method method = methods[i];
            NSLog(@"method's signature: %s", method_getName(method));
        }
        free(methods);
        Method method1 = class_getInstanceMethod(cls, @selector(method1));
        if (method1 != NULL) {
            NSLog(@"method %s", method_getName(method1));
        }
        Method classMethod = class_getClassMethod(cls, @selector(classMethod1));
        if (classMethod != NULL) {
            NSLog(@"class method : %s", method_getName(classMethod));
        }
        NSLog(@"MyClass is%@ responsd to selector: method3WithArg1:arg2:", class_respondsToSelector(cls, @selector(method3WithArg1:arg2:)) ? @"" : @" not");
        IMP imp = class_getMethodImplementation(cls, @selector(method1));
        imp();
        NSLog(@"==========================================================");
        // 协议
        Protocol * __unsafe_unretained * protocols = class_copyProtocolList(cls, &outCount);
        Protocol * protocol;
        for (int i = 0; i < outCount; i++) {
            protocol = protocols[i];
            NSLog(@"protocol name: %s", protocol_getName(protocol));
        }
        NSLog(@"MyClass is%@ responsed to protocol %s", class_conformsToProtocol(cls, protocol) ? @"" : @" not", protocol_getName(protocol));
        NSLog(@"==========================================================");
    }
    return 0;
}

2014-10-22 19:41:37.452 RuntimeTest[3189:156810] class name: MyClass
2014-10-22 19:41:37.453 RuntimeTest[3189:156810] ==========================================================
2014-10-22 19:41:37.454 RuntimeTest[3189:156810] super class name: NSObject
2014-10-22 19:41:37.454 RuntimeTest[3189:156810] ==========================================================
2014-10-22 19:41:37.454 RuntimeTest[3189:156810] MyClass is not a meta-class
2014-10-22 19:41:37.454 RuntimeTest[3189:156810] ==========================================================
2014-10-22 19:41:37.454 RuntimeTest[3189:156810] MyClass's meta-class is MyClass
2014-10-22 19:41:37.455 RuntimeTest[3189:156810] ==========================================================
2014-10-22 19:41:37.455 RuntimeTest[3189:156810] instance size: 48
2014-10-22 19:41:37.455 RuntimeTest[3189:156810] ==========================================================
2014-10-22 19:41:37.455 RuntimeTest[3189:156810] instance variable's name: _instance1 at index: 0
2014-10-22 19:41:37.455 RuntimeTest[3189:156810] instance variable's name: _instance2 at index: 1
2014-10-22 19:41:37.455 RuntimeTest[3189:156810] instance variable's name: _array at index: 2
2014-10-22 19:41:37.455 RuntimeTest[3189:156810] instance variable's name: _string at index: 3
2014-10-22 19:41:37.463 RuntimeTest[3189:156810] instance variable's name: _integer at index: 4
2014-10-22 19:41:37.463 RuntimeTest[3189:156810] instace variable _string
2014-10-22 19:41:37.463 RuntimeTest[3189:156810] ==========================================================
2014-10-22 19:41:37.463 RuntimeTest[3189:156810] property's name: array
2014-10-22 19:41:37.463 RuntimeTest[3189:156810] property's name: string
2014-10-22 19:41:37.464 RuntimeTest[3189:156810] property's name: integer
2014-10-22 19:41:37.464 RuntimeTest[3189:156810] property array
2014-10-22 19:41:37.464 RuntimeTest[3189:156810] ==========================================================
2014-10-22 19:41:37.464 RuntimeTest[3189:156810] method's signature: method1
2014-10-22 19:41:37.464 RuntimeTest[3189:156810] method's signature: method2
2014-10-22 19:41:37.464 RuntimeTest[3189:156810] method's signature: method3WithArg1:arg2:
2014-10-22 19:41:37.465 RuntimeTest[3189:156810] method's signature: integer
2014-10-22 19:41:37.465 RuntimeTest[3189:156810] method's signature: setInteger:
2014-10-22 19:41:37.465 RuntimeTest[3189:156810] method's signature: array
2014-10-22 19:41:37.465 RuntimeTest[3189:156810] method's signature: string
2014-10-22 19:41:37.465 RuntimeTest[3189:156810] method's signature: setString:
2014-10-22 19:41:37.465 RuntimeTest[3189:156810] method's signature: setArray:
2014-10-22 19:41:37.466 RuntimeTest[3189:156810] method's signature: .cxx_destruct
2014-10-22 19:41:37.466 RuntimeTest[3189:156810] method method1
2014-10-22 19:41:37.466 RuntimeTest[3189:156810] class method : classMethod1
2014-10-22 19:41:37.466 RuntimeTest[3189:156810] MyClass is responsd to selector: method3WithArg1:arg2:
2014-10-22 19:41:37.467 RuntimeTest[3189:156810] call method method1
2014-10-22 19:41:37.467 RuntimeTest[3189:156810] ==========================================================
2014-10-22 19:41:37.467 RuntimeTest[3189:156810] protocol name: NSCopying
2014-10-22 19:41:37.467 RuntimeTest[3189:156810] protocol name: NSCoding
2014-10-22 19:41:37.467 RuntimeTest[3189:156810] MyClass is responsed to protocol NSCoding
2014-10-22 19:41:37.468 RuntimeTest[3189:156810] ==========================================================

大米论坛(需注册):http://www.iminisd.com/forum.php(据说国产片/港产片资源很强大)

再来,便是虚荣心作祟的问题了。也有过文章上首页推荐的狂欢,但转眼发现,厄,怎么自家辛辛苦苦写的洪篇巨范没啥人看,随手涂抹的短篇倒是被荐被赞连连。一身兼具“世胄蹑高位,英俊沉下僚”二者。也曾经一见博客上有新动态便激动万分,无论留言、收藏、加好友,但事实上到今天就没收到过神马有质量的评论留言,倒是各种出书的,推广的广告居多,于是每天一打开页面都是怀着“世路如今已惯,看有啥新诈骗”的淡然,以爱咋的咋的的心态理智客观看待各种灌水去了。

动态创建类和对象

runtime的强大之处在于它能在运行时创建类和对象。
动态####创建类
动态创建类涉及到以下几个函数:

// 创建一个新类和元类
Class objc_allocateClassPair ( Class superclass, const char *name, size_t extraBytes );
// 销毁一个类及其相关联的类
void objc_disposeClassPair ( Class cls );
// 在应用中注册由objc_allocateClassPair创建的类
void objc_registerClassPair ( Class cls );
  • objc_allocateClassPair函数:如果我们要创建一个根类,则superclass指定为Nil。extraBytes通常指定为0,该参数是分配给类和元类对象尾部的索引ivars的字节数。

为了创建一个新类,我们需要调用objc_allocateClassPair。然后使用诸如class_addMethod,class_addIvar等函数来为新创建的类添加方法、实例变量和属性等。完成这些后,我们需要调用objc_registerClassPair函数来注册类,之后这个新类就可以在程序中使用了。

实例方法和实例变量应该添加到类自身上,而类方法应该添加到类的元类上。

  • objc_disposeClassPair函数用于销毁一个类,不过需要注意的是,如果程序运行中还存在类或其子类的实例,则不能调用针对类调用该方法。
    在前面介绍元类时,我们已经有接触到这几个函数了,在此我们再举个实例来看看这几个函数的使用。
Class cls = objc_allocateClassPair(MyClass.class, "MySubClass", 0);

class_addMethod(cls, @selector(submethod1), (IMP)imp_submethod1, "v@:");
class_replaceMethod(cls, @selector(method1), (IMP)imp_submethod1, "v@:");
class_addIvar(cls, "_ivar1", sizeof(NSString *), log(sizeof(NSString *)), "i");

objc_property_attribute_t type = {"T", "@"NSString""};
objc_property_attribute_t ownership = { "C", "" };
objc_property_attribute_t backingivar = { "V", "_ivar1"};
objc_property_attribute_t attrs[] = {type, ownership, backingivar};

class_addProperty(cls, "property2", attrs, 3);
objc_registerClassPair(cls);
id instance = [[cls alloc] init];
[instance performSelector:@selector(submethod1)];
[instance performSelector:@selector(method1)];

程序的输出如下:

2014-10-23 11:35:31.006 RuntimeTest[3800:66152] run sub method 1
2014-10-23 11:35:31.006 RuntimeTest[3800:66152] run sub method 1

KICKASS:http://kickass.to/(俗称“踢屁股”,也是个综合性种子站,新片老片应有尽有)

当然,谁也不是生活在真空罐子里,要不那来这许多可写的东西,写文的江湖原本就风险叵测,写的多了,也难免被卷在里面,湿了半只脚--趾头。对于这个问题,个人对自己的写文标准是,永远当成没有一个人看文,永远当成有无数人看文。写文原本就是自家事,主观精神就是:吐自己的槽,爱说啥说啥去吧,千万不能为那些不相干的人左右哇。就当自己是,原本一直是/在自说自话,不必管外面秋冬春夏,当然这只指写文,衣物还是要随时添减哒。那么那位说你不还说什么要当做有无数人看文的么,擦汗个,实话说,起先儿写写文的时候,有不少时候不知道如何描述事件经过,想不出如何转折,如何结尾,如何表达出自己想说的意思,第N次感慨说,这是一个多年以写文为职的人呢,你能相信么,当然令人足够欣慰的是俺还远不是最差的,前几天还听一位从事编辑工作的师兄吐槽说他家记者的稿件都是每天从新浪财经扒的,忍不住深刻鄙视之,并顺便说一句:你们就不能去看看网易财经、凤凰财经么?(非植入,但上述两家如果要给俺钱的话俺也没嘛意见哒)当然,本着“无他,手熟”的宇宙通用定律,写的多了,行文日渐顺畅,吐槽也越发欢快起来,文章似一早便存在脑子里面,俺只需当个打字员,各种花样敲键盘既可。所以俺曾多次在21日养成文中表示过,写文这小一年,俺工作上取得的最大进展就是打字快多了,只可惜而今没有打字员这个工种了。打字快了,也算装备升级了吧,虽然现在日更文的主流是千字文,但个人一向要求自己不能以千字以标准,要如行云流水,行所当行,止所当止,书尽其事。绝不能只写个三百五百字的糊弄事。在写文上可以骗别人,不能骗自己。虽然这年月做实的总输于玩虚的,花功夫下力气的结果大多然并卵,但整天在外面应酬完还要关起门来自己把自己骗这事未免太过悲惨,一定要努力避免再避免。好在虽然时间过半,任务过半,但想写的东西还有好多好多篇,口水连天的吐也吐不完,很多人遇到的所谓写的多了以后没有什么新鲜事可写了这事儿目前在俺身上是从未遇到过。当然也可能说那话的都是男生来的,他们不八卦么,可要写东西就得有双善于探索发现的眼睛不是,这点上女生比男生可强了真不止一点半点,生生超出一射之远。当然,这个世界是相对公平的,如果女生们肯把凑在一起八卦的时间用在干正事上,男生早就成了职场上的弱势群体了,脑洞再大一点,再如果女生们肯把化妆打扮的时间用在看书学习上,那么应该早就无敌于天下,重现母系氏族社会的荣光啰。好啦,好啦,说回写文吧---俺是补吃过脑残片的昏割线,不信你看文学史上N多著名作家都挺神经质的,不神经质怎么写出深入内心的作品来呦。

本文由奥门金沙网址发布于技术,转载请注明出处:当我在写千字文的时候我在写神马,类与对象

上一篇:阅读技巧,又发现了一款 下一篇:没有了
猜你喜欢
热门排行
精彩图文