iOS开发中的对象系统基础

[0] Outline

  -- [1] id和Class

  -- [2] 动态地操作类

  -- [3] 实例化

[1] id和Class

在Objective-C中有一个特别的数据类型作为对象标识符:id,可以指向任何类型的对象。

通过 “可以指向任何类型的对象” 这一描述,猜想id实际上是指向Objective-C对象系统中的基类(继承体系中的祖先结构)的指针,在运行时是指向对象内存布局的基类部分。

第一眼看到id数据类型,我联想到了Python中的PyObject结构:

typedef struct _object {
    int ob_refcnt;
    struct _typeobject *ob_type;
} PyObject;

该数据类型也是Python对象系统中的祖先类型,不过与id相对应的应该是PyObject *类型。

id数据类型是一个指向struct objc_object结构的指针:

typedef struct objc_class *Class;
typedef struct objc_object {
    Class isa;
} *id;

更确切地说,id是指向Class类型的指针,而Class又是指向struct objc_class结构的指针:

struct objc_class {
     struct objc_class *isa;

     struct objc_class *super_class;
     const char *name;
     long version;
     long info;
     long instance_size;
     struct objc_ivar_list *ivars;
     struct objc_method_list **methodLists;
     struct objc_cache *cache;
     struct objc_protocol_list *protocols;
};

至此,可以看到Objective-C对象系统的基石:struct objc_class结构:

     isa指针:指向该对象所属类型的类型对象(Class Object)。在Objective-C中,类也是用对象来表示的,而类的isa指针指向它的metaclass(存储静态成员变量和类方法)。
     super_class指针:指向父类。
     name:类名称。
     version:类的版本信息。
     info:运行期使用的标志位,比如0x1(CLS_CLASS)表示该类为普通class,0x2(CLS_META)表示该类为     metaclass。
     instance_size:实例大小,即内存所占空间。
     ivars:指向成员变量列表的指针。
     methodLists:根据标志位的不同可能指向不同,比如可能指向实例方法列表,或者指向类方法列表。
     cache:因为Objective-C的消息转发需要查找dispatch table甚至可能需要遍历继承体系,所以缓存最近使用的方法。
     protocols:类需要遵守的协议。

[2] 动态地操作类

由上知道了类也是一种对象,那么类对象也有一种类型,这种类型就是类的metaclass,因此类方法其实就是metaclass的成员方法,类和metaclass是配套出现的。

那么metaclass的isa指针和super_class指针怎么指向的呢?

如果metaclass对应基类,那么它的isa指向自身、super_class指针指向对应的类(基类);如果不是则isa指针指向基类的metaclass、super_class指针指向父类的metaclass。

基类的isa指针为nil。

这不禁让我又想起了Python中类似的设计思想,比如整型数字2的类型是PyIntObject,而PyIntObject类的类型是PyTypeObject,PyTypeObject的类型是PyTypeObject。最终止于此。

同样地,Python中也有metaclass的存在。

知道了类的表示结构,我们可以动态地对类进行操作,加深理解。

//
//  main.m
//  HelloOC
//
//  Created by Jason Lee on 12-2-17.
//  Copyright (c) 2012年 XXX. All rights reserved.
//

#import <Foundation/Foundation.h>

#import <objc/objc.h>
#import <objc/runtime.h>

void selfIntro(idself, SEL_cmd);

int main (int argc, constchar * argv[])
{

    @autoreleasepool {
        //Create class & metaclass as a pair
        Class demoClass = objc_allocateClassPair([NSObjectclass], "NSDemo", 0);

        BOOL isOk = NO;

        //"v@:" indicates the function type : v - void, @ - object, : - SEL
        //向methodLists指向添加数据
        isOk = class_addMethod(demoClass, @selector(intro), (IMP)&selfIntro, "v@:");
        isOk == YES ? nil : NSLog(@"failed on class_addMethod\n");

        //向ivars指向添加数据
        isOk = class_addIvar(demoClass,"myVar", sizeof(id), log2(sizeof(id)), "@");
        isOk == YES ? nil : NSLog(@"failed on class_addIvar\n");

        objc_registerClassPair(demoClass);

        id demo = class_createInstance(demoClass, 0);

        if ([demo respondsToSelector:@selector(intro)]) {
            [demo performSelector:@selector(intro)];
        }

        object_setInstanceVariable(demo, "myVar", nil);
        void *outValue = (void *)0x1;
        object_getInstanceVariable(demo, "myVar", &outValue);
        if (nil == outValue) {
            NSLog(@"Hello,nil\n");  //printed
        }

        object_dispose(demo);
    }

    return0;
}

void selfIntro(idself, SEL_cmd) {
    NSLog(@"selfIntro\n");

    Class isa = self->isa;  //At first, isa is class NSDemo
    while (1) {
        if (isa == isa->isa) {  //Finally, NSObject's metaclass points to itself
            NSLog(@"%p, %@", isa, objc_getMetaClass(class_getName([isa class])));
            break;
        }

        NSLog(@"%p, %@", isa, objc_getMetaClass(class_getName([isa class])));
        isa = isa->isa; //Then, isa is assigned to NSDemo's metaclass
    }
}

[3] 实例化

要实例化出一个对象,需要根据类的定义来进行。类的定义包括类名称、数据和操作数据的方法。

编译过程,类的信息会被记录下来,供runtime system使用,同时编译器会为每个类创建唯一的一个对象来表示它:class object。如果从功能上说,class object也是factory object,它能够执行类方法,负责创建实例。

从这个角度来看,我在思考class object是否就是metaclass,但是不能确认。

Apple官方文档TOCPL中Class Objects一章有这么一句,“a class object keeps the prototype of a class instance”,但metaclass并不能作为实例原型。

于是我认为class object是运行时class和metaclass结合起来的受限表现,能够访问编译器捕捉下来的类信息,没有成员变量,不能调用成员方法,但是可以执行类方法。

从源码层次来看,class object是由类名来表示,比如下述代码中:

int version = [NSString version];

NSString代表着class object。

首先,class object会被runtime system发送initialize消息进行初始化,让其做好运行时的准备,比如初始化静态变量。

之后,可以调用class object的方法(类方法)alloc来为新的实例对象分配内存空间,将其所有变量初始化为0,isa指针指向所属类。

最后再调用init函数进行必要的初始化。

写到这里的时候,突然要变更办公位置,思路被打断了,就先写到这里。

最后,留一个在SO上面看到的问题,我也疑惑,只能有几分猜测:http://stackoverflow.com/questions/8847146/whats-is-methodlists-attribute-of-the-structure-objc-class-for

[这篇文章是我对SO上的问题的解答:http://blog.csdn.net/jasonblog/article/details/7303618]

[Last Updated] 2012-03-17

Jason Lee @ 杭州

博客:http://blog.csdn.net/jasonblog

微博:http://weibo.com/jasonmblog

GitHub: https://github.com/siqin

时间: 2024-11-02 20:27:55

iOS开发中的对象系统基础的相关文章

iOS开发中的播放系统音效和自定义音效

需求大致分为三种: 1.震动 2.系统音效(无需提供音频文件) 3.自定义音效(需提供音频文件) 我的工具类的封装: // // WQPlaySound.h // WQSound // // Created by 念茜 on 12-7-20. // Copyright (c) 2012年 __MyCompanyName__. All rights reserved. // #import <UIKit/UIKit.h> #import <AudioToolbox/AudioToolbox

iOS开发中各种关键字的区别

一.一些概念 浅Copy:指针的复制,只是多了一个指向这块内存的指针,共用一块内存. 深Copy:内存的复制,两块内存是完全不同的, 也就是两个对象指针分别指向不同的内存,互不干涉. atomic是Objc使用的一种线程保护技术, 基本上来讲,是防止在写未完成的时候被另外一个线程读取, 造成数据错误.而这种机制是耗费系统资源的, 所以在iPhone这种小型设备上,如果没有使用多线程间的通讯编程,那么nonatomic是一个非常好的选择. 二.各种属性的解析 weak: <修饰Object类型,A

iOS开发中使用UIScrollView实现无限循环的图片浏览器_IOS

一.概述 UIKit框架中有大量的控件供开发者使用,在iOS开发中不仅可以直接使用这些控件还可以在这些控件的基础上进行扩展打造自己的控件.在这个系列中如果每个控件都介绍一遍确实没有必要,所谓授人以鱼不如授人以渔,这里会尽可能让大家明白其中的原理,找一些典型的控件进行说明,这样一来大家就可以触类旁通.今天我们主要来看一下UIScrollView的内容: UIView UIScrollView 实战--图片浏览器 二.UIView 在熟悉UIScrollView之前很有必要说一下UIView的内容.

ios开发中时间转换的方法集锦

  这篇文章主要介绍了ios开发中时间转换的方法集锦,需要的朋友可以参考下 在开发iOS程序时,有时候需要将时间格式调整成自己希望的格式,这个时候我们可以用NSDateFormatter类来处理. 例如: //实例化一个NSDateFormatter对象 NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init]; //设定时间格式,这里可以设置成自己需要的格式 [dateFormatter setDateFormat:@"yy

iOS开发中的手势体系——UIGestureRecognizer分析及其子类的使用

iOS开发中的手势体系--UIGestureRecognizer分析及其子类的使用 一.引言         在iOS系统中,手势是进行用户交互的重要方式,通过UIGestureRecognizer类,我们可以轻松的创建出各种手势应用于app中.关于UIGestureRecognizer类,是对iOS中的事件传递机制面向应用的封装,将手势消息的传递抽象为了对象.有关消息传递的一些讨论,在前面的博客中有提到: iOS事件响应控制:http://my.oschina.net/u/2340880/bl

iOS 开发中的 Flux 架构模式

本文讲的是iOS 开发中的 Flux 架构模式, 在半年前,我开始在 PlanGrid iOS 应用程序中采用 Flux 架构(开发).这篇文章将会讨论我们从传统的 MVC 转换到Flux的动机,同时分享我们目前积累到的经验. 我尝试通过讨论代码来描述我们大部分的 Flux 实现, 它用于我们今天的产品中. 如果你只对综合结果感兴趣, 请跳过这篇文章的中间部分. 为什么从 MVC 转移 为了引入我们的决定, 我想要先谈一谈 PlanGrid 这个应用遇到的一些挑战.一些问题仅针对企业级应用程序,

IOS开发中常用的设计模式

说起设计模式,感觉自己把握不了笔头,所以单拿出iOS开发中的几种常用设计模式谈一下. 单例模式(Singleton) 概念:整个应用或系统只能有该类的一个实例. 在iOS开发我们经常碰到只需要某类一个实例的情况,最常见的莫过于对硬件参数的访问类,比如UIAccelerometer.这个类可以帮助我们获得硬件在各个方向轴上的加速度,但是我们仅仅需要它的一个实例就够了,再多,只会浪费内存. 所以苹果提供了一个UIAccelerometer的实例化方法+sharedAccelerometer,从名字上

ios开发中两个常见问题解决方法

  ios开发中两个常见问题解决方法来啦!大家知道苹果手机使用的是ios系统,而且用户量很庞大,所以ios开发也成了很热门的行业.下文小乐哥给大家带来ios开发中两个常见问题解决方法,希望给技术员在ios开发中起到帮助作用! ios开发中两个常见问题解决方法 一."Unknown class XXViewController in Interface Builder file."问题处理 最近在静态库中写了一个XXViewController类,然后在主工程的xib中,将xib的类指定

iOS开发中标签控制器的使用——UITabBarController

iOS开发中标签控制器的使用--UITabBarController 一.引言         与导航控制器相类似,标签控制器也是用于管理视图控制器的一个UI控件,在其内部封装了一个标签栏,与导航不同的是,导航的管理方式是纵向的,采用push与pop切换控制器,标签的管理是横向的,通过标签的切换来改变控制器,一般我们习惯将tabBar作为应用程序的根视图控制器,在其中添加导航,导航中在对ViewController进行管理. 二.创建一个标签控制器         通过如下的步骤,我们可以很简便