Objective-C Runtime的数据类型

转自:http://www.cnblogs.com/whyandinside/archive/2013/02/26/2933552.html

Class

Objective-C是支持反射的,先来了解一下其如何表达一个类。在Objective-C的Runtime中有个类型是Class(只在Runtime环境中使用),用来表示Objective-C中的类,其定义为:

typedef struct objc_class *Class;

可以看出,其实Class类型是一个指针,指向struct  objc_class,而struct  objc_class才是保存真正数据的地方,再看struct  objc_class的声明(from http://www.opensource.apple.com/source/objc4/objc4-493.9/runtime/runtime.h):

复制代码
struct objc_class {Class isa;#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;
复制代码

其中包含了方法列表、父类等信息,详细的可以稍后再看。

 

Method

是Runtime内部定义的方法,用来代表一个方法,其声明如下:

typedef struct objc_method *Method;

而struct  objc_method的声明如下:

struct objc_method {SEL method_name                                          OBJC2_UNAVAILABLE;char *method_types                                       OBJC2_UNAVAILABLE;IMP method_imp                                           OBJC2_UNAVAILABLE;
}

SEL和IMP代表什么需要看下面的内容。如果你已经了解了SEL和IMP的含义,可以看看下面这段:根据Class和Method的定义来理解Objective C中的消息机制:

先看看objc_class中method list的在runtime(http://opensource.apple.com/source/objc4/objc4-437/runtime/objc-runtime-new.h)里的定义:

复制代码
typedef struct method_list_t {uint32_t entsize_NEVER_USE;  // low 2 bits used for fixup markers
    uint32_t count;struct method_t first;
} method_list_t;typedef struct method_t {SEL name;const char *types;IMP imp;
} method_t;
复制代码

SEL相当于char*,可以认为objc_class中method list保存了一个SEL<->IMP的映射,看下面的代码:

Bird * aBird = [[Bird alloc] init];[aBird fly];

其中对fly的调用,其实是由编译器插入了一些代码,根据SEL([aBird fly] 中的fly就是SEL)找到了IMP,从而进行调用的。下面看编译器插入了什么样的代码。我们来看Objective C runtime中跟msg相关的函数:

id objc_msgSend(id theReceiver, SEL theSelector, ...)

这个函数发送消息给theReceiver,并将返回值返回。编译器其实就是将[aBird fly]转化成了对objc_msgSend的调用,从而实现消息机制的。objec_msgSend()函数将会使用theReceiver的isa指针来找到theReceiver的类空间结构并在类空间结构中查找theSelector所对应的方法。如果没有找到,那么将使用指向父类的指针找到父类空间结构进行theSelector的查找。如果仍然没有找到,就继续往父类的父类一直找,直到找到为止。如果找不到怎么办呢?关于消息机制,有一篇引用文章,介绍的更加详细,这里就不赘述。

 

Ivar

Runtime中用来表示instance variable(实例变量,跟某个对象关联,不能被静态方法使用,与之想对应的是class variable),其声明如下:

typedef struct objc_ivar *Ivar;

而struct objc_ivar的声明如下:

复制代码
struct objc_ivar {char *ivar_name                                          OBJC2_UNAVAILABLE;char *ivar_type                                          OBJC2_UNAVAILABLE;int ivar_offset                                          OBJC2_UNAVAILABLE;
#ifdef __LP64__int space                                                OBJC2_UNAVAILABLE;
#endif
}                                                            OBJC2_UNAVAILABLE;
复制代码

Category

Runtime中用来表示Category( link ?),其声明为:

typedef struct objc_category *Category;

struct objc_category 的定义也在runtime.h文件中。

[]Catagory可以动态地为已经存在的类添加新的行为。这样可以保证类的原始设计规模较小,功能增加时再逐步扩展。使用Category对类进行扩展时,不需要访问其源代码,也不需要创建子类。Category使用简单的方式,实现了类的相关方法的模块化,把不同的类方法分配到不同的分类文件中。下面看一个例子:

SomeClass.h
@interface SomeClass : NSObject{
}
-(void) print;
@end 

这是类SomeClass的声明文件,其中包含一个实例方法print。如果我们想在不修改原始类、不增加子类的情况下,为该类增加一个hello的方法,只需要简单的定义两个文件SomeClass+Hello.h和SomeClass+Hello.m,在声明文件和实现文件中用“()”把Category的名称括起来即可。声明文件代码如下:

#import "SomeClass.h"@interface SomeClass (Hello)
-(void)hello;
@end

实现文件代码如下:

#import "SomeClass+Hello.h"
@implementationSomeClass (Hello)
-(void)hello{NSLog (@"name:%@ ", @"Jacky");
}
@end

其中Hello是Category的名称,如果你用XCode创建Category,那么需要填写的内容包括名称和要扩展的类的名称。这里还有一个约定成俗的习惯,将声明文件和实现文件名称统一采用“原类名+Category”的方式命名。
调用也非常简单,毫无压力,首先引入Category的声明文件,然后正常调用即可:

#import "SomeClass+Hello.h"SomeClass * sc =[[SomeClass alloc] init];
[sc hello] 

执行结果是:
name:Jacky 

Category的使用场景:
1、当你在定义类的时候,在某些情况下(例如需求变更),你可能想要为其中的某个或几个类中添加方法。
2、一个类中包含了许多不同的方法需要实现,而这些方法需要不同团队的成员实现
3、当你在使用基础类库中的类时,你可能希望这些类实现一些你需要的方法。

遇到以上这些需求,Category可以帮助你解决问题。当然,使用Category也有些问题需要注意,
1、Category可以访问原始类的实例变量,但不能添加变量,如果想添加变量,可以考虑通过继承创建子类。
2、Category可以重载原始类的方法,但不推荐这么做,这么做的后果是你再也不能访问原来的方法。如果确实要重载,正确的选择是创建子类。
3、和普通接口有所区别的是,在分类的实现文件中可以不必实现所有声明的方法,只要你不去调用它。

用好Category可以充分利用Objective-C的动态特性,编写出灵活简洁的代码。

 

SEL

Runtime中用来表示一个method selector,其声明为:

typedef struct objc_selector     *SEL;

没有找到struct objc_selector的定义,有人说是编译器定义的,GCC 和MacOSX的实现方式还不一样,不想花时间找GCC的代码,而且也没那么重要,所以就先姑且相信这个说法吧。

IMP

IMP是一个函数指针,指向方法的实现,其定义为:

id (*IMP)(id, SEL, ...)

其所指向的方法,返回一个id(Cocoa 对象),需要传入的第一个参数是self(指向某个对象,或者一个类),第二个参数是方法的SEL。

objc_property_t

objc_method_list

objc_cache

objc_protocol_list

id

在 Objective-C中id类型的对象可以转换为任何一种对象,有点类似与void *指针类型的作用。下面简要介绍一下id类型。

id标志符:通用对象类型。id类型是一个独特的数据类型,可以转换为任何数据类型,即id类型的变量可以存放任何数据类型的对象。id在objc.h中的定义为:

typedef struct objc_object {Class isa;
} *id;

从上面的介绍,我们已经知道Class是struct  objc_class的指针别名,所以id可以指向一个第一个元素是Class的struct;那么它为什么可以指向NSObject对象呢?下面看NSObject的定义:

@interface NSObject <NSObject> {Class    isa;
}

可以看出NSObject的第一个对象是Class类型的isa。因为第一个元素相同,也就意味着可以互相cast而不损失信息,下面是用C语言来演示的其实现原理:

复制代码
#include <stdio.h>
#include <stdlib.h>
struct objc_class
{int count;char * name;
};typedef struct objc_class * Class;
typedef struct objc_obj0
{Class isa;
}*id;typedef struct objc_obj1
{Class isa;int a;
}*id1;typedef struct objc_obj2
{Class isa;char *b;
}*id2;int main(int argc, char **argv)
{// id 的第一个元素与id1是一样的,所以可以用id指向id1的元素,而不损失任何信息,不过后续使用的时候应该使用其实际类型id a = (struct objc_obj1 *)malloc(sizeof(struct objc_obj1)); id b = (struct objc_obj1 *)malloc(sizeof(struct objc_obj1)); 
}
复制代码

实施上,通常而言,这样使用时编译器是要report warning的,我们可以在.m文件中加入下面的代码来验证:

typedef struct objc_object *id2;id2 = [[NSNumber alloc] initWithInt:(i*3)];

这时是会报incompatible pointer types initializing 'id2' (aka 'struct objc_object *') with an expression of type 'NSNumber *' 的,但id2和id的定义相同,为什么使用id时不会有这个warning呢?因为编译器对id做了特殊处理,不报warning。这下对id有了更多了解了吧。后续而来的问题就是,为什么可以在id类型上调用一些NSNumber上才有的方法呢?这一部分留到Dynamic Typing and Dynamic binding时再说吧。 

 

http://unixjunkie.blogspot.com/2008/03/id-vs-nsobject-vs-id.html

http://www.cppblog.com/kesalin/archive/2011/08/15/objc_message.html

http://www.cnblogs.com/chijianqiang/archive/2012/06/22/objc-category-protocol.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/247073.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

CSS3制作文字背景图

文字带上渐变色&#xff0c;或者说让文字透出图片。这些效果 CSS 属性也可以完成。 方法一、利用CSS3属性mix-blend-mode:lighten;实现 使用 mix-blend-mode 能够轻易实现&#xff0c;我们只需要构造出黑色文字&#xff0c;白色底色的文字 div &#xff0c;叠加上图片&#xff…

HTTP基本认证

HTTP质询/响应认证框架 HTTP提供了一个原生的质询/响应框架&#xff0c;简化了对用户的认证过程。HTTP的认证模型如图所示. Web服务器接收到一条HTTP请求报文时&#xff0c;服务器没有直接响应请求的资源&#xff0c;而是以一个“认证质询”进行响应&#xff0c;要求用户提供一…

单行、多行文本超出显示省略号

前言&#xff1a;项目中我们经常遇到这种需求&#xff0c;需要对单行、多行文本超出显示为省略号。这篇文章主要总结了小编解决此问题的方法&#xff0c;有不足之处欢迎大家指正。单行文本省略 .ellipsis-line {border: 1px solid #f70505;padding: 8px;width: 400px;overflow:…

数据归一化matlab及python 实现

更多细节请查看 https://www.zhihu.com/question/20455227 归一化的目的简而言之&#xff0c;是使得没有可比性的数据变得具有可比性&#xff0c;同时又保持相比较的两个数据之间的相对关系。 归一化首先在维数非常多的时候&#xff0c;可以防止某一维或某几维对数据影响过大…

机器学习综述

机器学习综述 摘要 本文主要参考中科院自动化研究所复杂系统与智能科学实验室王珏研究员《关于机器学习的讨论》&#xff0c;讨论机器学习的描述&#xff0c;理论基础&#xff0c;发展历史以及研究现状。 关键字:机器学习&#xff0c;科学依据&#xff0c;发展脉络 0引言 20世纪…

递归锁、信号量、GIL锁、基于多线程的socket通信和进程池线程池

递归锁、信号量、GIL锁、基于多线程的socket通信和进程池线程池 递归锁 死锁现象&#xff1a;是指两个或两个以上的进程和线程因抢夺计算机资源而产生的一种互相等待的现象 from threading import Thread from threading import Lock import time lock_A Lock() lock_B Lock(…

10 种机器学习算法的要点(附 Python 和 R 代码)

前言 谷歌董事长施密特曾说过&#xff1a;虽然谷歌的无人驾驶汽车和机器人受到了许多媒体关注&#xff0c;但是这家公司真正的未来在于机器学习&#xff0c;一种让计算机更聪明、更个性化的技术。 也许我们生活在人类历史上最关键的时期&#xff1a;从使用大型计算机&#xff0…

阻塞、非阻塞、同步与异步

阻塞、非阻塞、同步与异步 阻塞与非阻塞 进程运行的三种状态&#xff1a;运行、就绪、阻塞 阻塞和非阻塞&#xff1a; ​ 阻塞&#xff1a;程序运行时,遇到了IO,程序挂起,cpu被切走. ​ 非阻塞&#xff1a; 程序没有遇到IO,程序遇到IO但是我通过某种手段,让cpu强行运行我的程序…

8大策略让你对抗机器学习数据集里的不均衡数据

本文转自&#xff1a;http://www.36dsj.com/archives/35137 http://blog.csdn.net/heyongluoyao8/article/details/49408131 英文版本&#xff1a;http://machinelearningmastery.com/tactics-to-combat-imbalanced-classes-in-your-machine-learning-dataset/ 你是不是也经历…

线程queue、事件event及协程

线程queue、事件event及协程 线程queue 多线程抢占资源&#xff0c;让其保持串行的两种方式&#xff1a; ​ 1、互斥锁 ​ 2、队列 线程队列分为以下三种&#xff1a; 1、Queue&#xff08;先进先出&#xff09; import queueq queue.Queue(3) q.put(1) q.put(2) q.put(3) # q…

不平衡数据下的机器学习方法简介

本文转自&#xff1a;http://baogege.info/2015/11/16/learning-from-imbalanced-data/ 引言 不管是在学术界还是工业界&#xff0c;不平衡学习已经吸引了越来越多的关注&#xff0c;不平衡数据的场景也出现在互联网应用的方方面面&#xff0c;如搜索引擎的点击预测&#xff08…

CSS预处理——LESS

LESS是什么&#xff1f; less是一门CSS预处理语言。由于CSS本身并不是程序式语言&#xff0c;不方便维护和扩展&#xff0c;没有变量、函数、作用域等概念。而LESS在CSS的基础语法之上&#xff0c;引入了变量、Mixin混入、运算以及函数等功能&#xff0c;大大简化了CSS的编写&a…

不均衡数据的处理方法

关于不均衡数据的处理方法&#xff0c;主要有以下几个方面&#xff1a; 1. 采样的方法 1.1 过采样&#xff0c;采集类标少的样本&#xff0c;达到平衡样本的目的。 方法一&#xff0c;简单的复制类标少的样本 方法二&#xff0c;生成人工样本&#xff08;SMOTE方法&#xff09…

.mat,.txt,.csv 数据转换为weka中的arff格式及matlab和Weka之间相互转换格式

在RUSBoost和SMOTEBoost中提供了csv转换为arff格式的方法&#xff0c;详见CSVtoARFF.m http://www.mathworks.com/matlabcentral/fileexchange/37315-rusboost http://cn.mathworks.com/matlabcentral/fileexchange/37311-smoteboost function r CSVtoARFF (data, relation…

IT人不仅要提升挣钱能力,更要拓展挣钱途径

前几天我上班路上&#xff0c;和小区门口开车的师傅闲聊&#xff0c;发现他们虽然学历不高&#xff0c;但挣钱的途径不少&#xff0c;比如固定接送多位客户&#xff0c;然后能通过朋友圈拓展新客户&#xff0c;而且通过客户口口相传&#xff0c;也能不断拉到生意&#xff0c;算…

Class Imbalance Problem

本文转自&#xff1a;http://www.chioka.in/class-imbalance-problem/#comment-202282 What is the Class Imbalance Problem? It is the problem in machine learning where the total number of a class of data (positive) is far less than the total number of another c…

matlab中的类标转换程序

matlab中的类标转换程序 原始类标为Y&#xff0c;新类标为Y_new %进行排序&#xff0c;针对类标数目orig_labels sort(unique(Y)); Y_new Y;new_labels 1:length(orig_labels);for i1:length(orig_labels)Y_new(find(Yorig_labels(i)))Inf;Y_new(isinf(Y_new))new_labels(…

this关键字+super关键字

一.this关键字1.实例一&#xff1a;&#xff08;1&#xff09;需求&#xff1a;使用Java类描述一个动物&#xff1b;&#xff08;2&#xff09;实例&#xff1a;class Animal{ String name; //成员变量 String color; public Animal(String n,String c){ na…

python中的print

python3 中去除了print语句&#xff0c;加入print()函数实现相同的功能 print() 会在输出窗口中显示一些文本。 >>> print "hello,world!" SyntaxError: Missing parentheses in call to print >>> print("hello,world!") hello,world…

final+static

final final关键字顾名思义代表“最后的”&#xff0c;意味着不能被更改。它的定义&#xff0c;可以概括地分为以下三点&#xff1a; 被final修饰的类不能被继承&#xff1b;被final修饰的方法不能被重写&#xff1b;被final修饰的变量不能被改变。注&#xff1a;引用类型的变量…