讨论Objective-C的一个奇怪的概念 meta-class
 
在Objective-C中的每个类,都有它自己相关的meta-class,但因为你很少直接使用meta-class,所以显得很神秘。
 
在运行时建立一个类
 
下面的代码在运行时创建一个NSError新的子类,并添加一个方法到里面:
 
 Class newClass =
    objc_allocateClassPair([NSError class], “RuntimeErrorSubclass”, 0);
 class_addMethod(newClass, @selector(report), (IMP)ReportFunction, “v@:”);
 objc_registerClassPair(newClass);
 
添加的这个方法用ReportFunction函数名作为它的实现,实现定义在下面
 
void ReportFunction(id self, SEL _cmd)
 {
    NSLog(@”This object is %p.”, self);
    NSLog(@”Class is %@, and super is %@.”, [self class], [self superclass]);
  
    Class currentClass = [self class];
    for (int i = 1; i < 5; i++)
    {
        NSLog(@”Following the isa pointer %d times gives %p”, i, currentClass);
        currentClass = object_getClass(currentClass);
    }
  
    NSLog(@”NSObject’s class is %p”, [NSObject class]);
    NSLog(@”NSObject’s meta class is %p”, object_getClass([NSObject class]));
 }
 
表面上,这都很简单。在运行时创建一个新类,只需要3步
 
1)为 class pair分配存储空间 (使用objc_allocateClassPair)
 
2)增加需要的方法和ivars(使用class_addMethod来添加方法)
 
3) 注册这个类,以便它能被别人使用(objc_registerClassPair)

现在的问题是,什么是class pair, 函数objc_allocateClassPair只返回一个值:the class
 
那么pair的另外一半在哪里呢?你可能已经猜到另外一般就是meta-class(也就是本文的主题)
 
一个数据结构需要哪些东西才能成为一个对象
 
每个对象都有一个类,这是一个基本的面向对象的概念。
 
在Objective-C中,任何数据结构,如果在正确的位置有一个指向类的指针,就能被视为一个对象。
 
在Objective-C中,一个对象的类,由它的isa指针决定。这个isa指针指向 对象的类。
 
事实上,一个对象的基本定义是这样的:
 
typedef struct objc_object {
 
    Class isa;
 
} *id;
 
这就是说,任何以一个指向Class结构的指针开始的结构,都能被当作objc_object
 
对象最重要的特性,就是你可以给它们发送消息:
 
[@"stringValue"
 
    writeToFile:@"/file.txt" atomically:YES encoding:NSUTF8StringEncoding error:NULL];
 
 
当你发送消息给一个Objective-C对象时(比如这里的NSCFString), 运行时(runtime) 通过对象的isa指针得到对象的Class(这里是NSCFString类),而Class里含有那些可以应用这个类的所有对象上的所有方法的列表,以及指向superclass的指针。运行时通过类的方法列表和超类,来发现一个能同消息选择子匹配的方法(上面的例子中,就是在NSString类中的writeToFile:atomically:encoding:error方法)。
 
要点就是:类定义了那些消息,你只能发送那些已经定义好的消息给它的对象
 
什么是meta-class
 
现在,你可能已经知道,在Objective-C中,一个类也是一个对象。这意味着,你也可以发送消息给一个类
 
NSStringEncoding defaultStringEncoding = [NSString defaultStringEncoding];
 
在这种情况下, defaultStringEncoding被发送给NSString类
 
在Objective-C 中,每个类,都是一个对象。也就是说,类结构也必须以isa指针开始,这样,它才同objc_object结构二进制兼容
 
在结构里的第2个项目,必须是superclass的指针(如果是基类,没有父类的话,设置为nil)
 
定义一个类,有很多不同的方式,依赖于你的运行时版本而不同,但他们都以 isa开始,然后后面接着superclass
 
typedef struct objc_class *Class;
 
struct objc_class {
 
    Class isa;
 
    Class super_class;
 
    /* followed by runtime specific details… */
 
};
 
为了让我们调用类的一个方法,类的isa指针必须指向一个类结构,并且,类结构必须含有我们能在该类上调用的方法列表
 
这就导致了一个meta-class的定义:meta-class是一个类对象的类
 
简单地说,

当你发送一条消息给一个对象时,这条消息会在对象的类的方法列表里查找
 
当你发送一条消息给一个类时,就会在类的meta-class的方法列表理查找消息
 
meta-class是必不可少的,因为它存储了一个类的类 方法。每个类都必须只有唯一的meta-class,因为每个类都只可能有一个唯一的类方法列表。
 
meta-class的类又是什么呢?
 
meta-class,跟 类一样,它也是一个对象。这意味着,你也可以在它上面调用方法。自然地,这意味这,它也必须有一个类。
 
所有的meta-class都使用基类的meta-class(在它们的继承体系中,最顶层的类的meta-class)作为它们自己的类。这意味着,所有从NSObject继承来的类,它们的meta-class都将NSObject的meta-class作为自己的类
 
遵循这个规则,所有的meta-class使用基类的meta-class作为它们自己的类,任何base meta-class都将是它自己的类(它们的isa指针指向它们自己)。也就是说,在 NSObject的meta-class的isa指针将指向它自己(它是自己的一个实例)
 
类和 meta-class的继承
 
同样的方式,类用super_class 指针指向超类,meta-class使用它自己的super_class指向 类的super-class的meta-class
 
巧合地是,基类的meta-class设置它的 super_class 为基类自己。

用实验来验证我们的想法
 
为了确认这些情况,我们看看ReportFunctional的输出。 这个函数的目的是 追踪isa指针,并记录在哪里找到的它。
 
为了运行ReportFunction,我们需要建立这个动态创建的类的实例,然后调用它的report方法
 
id instanceOfNewClass =
 
    [[newClass alloc] initWithDomain:@”someDomain” code:0 userInfo:nil];
 
[instanceOfNewClass performSelector:@selector(report)];
 
[instanceOfNewClass release];
 
因为没有report方法的声明,我使用performSelector:来调用它,所以编译不会给出什么警告 
 
ReportFunction将遍历isa指针,告诉我们那些对象被当成类,meta-class,以及meta-class的类 来使用
 
取得一个对象的类:ReportFunction将使用object_getClass来追踪isa指针, 因为isa指针是类的一个被保护的成员(你不能直接访问其他类的isa指针)
 
ReportFunction不使用类方法来实现这个,因为调用一个类对象的类方法,将不会返回meta-class. 而是再次返回这个类(所以[NSString class]将返回NSString类,而不是NSString的meta-class)
 
结论:
 
meta-class是类对象的类。每个类都有它自己唯一的meta-class(因为每个类都有它自己唯一的方法列表)

Objective-C中的meta-class的更多相关文章

  1. HTML中的meta(转载)

    meta是用来在HTML文档中模拟HTTP协议的响应头报文.meta 标签用于网页的<head>与</head>中,meta 标签的用处很多.meta 的属性有两种:name和 ...

  2. 使用CSS中的meta实现web定时刷新或跳转的方法

    这篇文章主要介绍了使用CSS中的meta实现web定时刷新或跳转的方法,比使用JavaScript脚本实现起来更加简单一些,需要的朋友可以参考下 meta源信息功能之页面定时跳转与刷新 几乎所有的网页 ...

  3. 理解Objective C 中id

    什么是id,与void *的区别 id在Objective C中是一个类型,一个complier所认可的Objective C类型,跟void *是不一样的,比如一个 id userName, 和vo ...

  4. 浅谈Objective—C中的面向对象特性

    Objective-C世界中的面向对象程序设计 面向对象称程序设计可能是现在最常用的程序设计模式.如何开发实际的程序是存在两个派系的-- 面向对象语言--在过去的几十年中,很多的面向对象语言被发明出来 ...

  5. objective C中的字符串NSStirng常用操作

    objective C中的字符串操作 在OC中创建字符串时,一般不使用C的方法,因为C将字符串作为字符数组,所以在操作时会有很多不方便的地方,在Cocoa中NSString集成的一些方法,可以很方便的 ...

  6. HTML中的<meta>标签的使用

    HTML中<meta>标签的使用 在我们制作的网页中,要是想让它能够让更多的人去访问,最好的方法就是通过搜索引擎来找到你的网址,于是需要你的网页可以有关键词能够让搜索引擎来识别,于是HTM ...

  7. html中的meta详解

    1  name=viewport <meta name="viewport" content="width=device-width,initial-scale=1 ...

  8. Objective C中的ARC的修饰符的使用---- 学习笔记九

    #import <Foundation/Foundation.h> @interface Test : NSObject /** * 默认的就是__strong,这里只是做示范,实际使用时 ...

  9. 移动web app 中的meta 标签

    <meta name="viewport" content="width=device-width; initial-scale=1.0; maximum-scal ...

  10. 清除ASPX页面中的meta:resourceKey="[a-zA-Z0-9]+"

    在替换对话框中,选中“使用正则表达式”, 被替换内容,使用 meta:resourceKey="[a-zA-Z0-9]+" 然后替换整个文档就可以了.

随机推荐

  1. poj2796 Feel good

    题目给出N个数,找出一段区间使得区间最小值乘区间和的值最大 其中N<=100000 分析: 单调队列(单调栈) 求出每个值作为最小值时最长的影响区间,然后枚举判断 这找出最长影响区间应该算是单调 ...

  2. spring4-5-事务管理

    1.简单介绍 事务管理是企业级应用程序开发中必不可少的技术,  用来确保数据的完整性和一致性. 事务就是一系列的动作, 它们被当做一个单独的工作单元. 这些动作要么全部完成, 要么全部不起作用 事务的 ...

  3. RabbitMQ EasyNetq 用法

    EasyNETQ帮助类 public class MQHelper { /// <summary> /// 发送消息 /// </summary> public static ...

  4. Linux cheat命令

    一.简介 cheat是在GNU通用公共许可证下,为Linux命令行用户发行的交互式备忘单应用程序.它提供显示Linux命令使用案例,包括该命令所有的选项和简短但尚可理解的功能. 二.安装配置 安装步骤 ...

  5. code3027 线段覆盖2

    dp 数据:d[i].a d[i].b d[i].v 分别表示第i条线段的起始点,结束点,价值 先按d[i].b排好序 dp[i]表示前i条线段的最大价值 方程: dp[i]=max{ dp[i-1] ...

  6. 拖拽demo--兼容--全局捕获

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

  7. CSS选择器种类及介绍

    首先说主都有哪些先择器 1.标签选择器(如:body,div,p,ul,li) 2.类选择器(如:class="head",class="head_logo") ...

  8. CodeForces 342A Xenia and Divisors (水题)

    题意:给定 n 个数(小于等于7),让你把它分成 m 组,每组有三个数,且满足,a < b < c,并且 a 能整除 b,b 能整除 c. 析:对于这个题,因为题目说了是不大于7的,那么一 ...

  9. Mac上phantomjs装了不能用的解决

    下了,装了.然后整这句命令: phantomjs --version 直接报错.. 查了半天的官方文档,居然连个毛线都么找到.终于...墨迹到了一个方法,就抱着试一试的心态在terminal里输入了这 ...

  10. spring mvc 入门程序

    入门程序 1.环境准备 myeclipse Spring jar 2.前端控制器设置 (web.xml) 所有的*.action请求通过org.springframework.web.servlet. ...