iOS类添加方法、属性学习笔记

一、在运行时为类添加方法

我们首先定义了一个EmptyClass,继承NSObject,没有任何自带方法,接着定义了一个函数。这里提一句,Obj-C的方法(method)就是一个至少需要两个参数(self,_cmd)的C函数,这个函数仅仅输出一句Hello。接下来在addMethod方法中,我们调用class_addMethod()为EmptyClass添加方法,class_addMethod()是这样定义的:

BOOL class_addMethod(Class cls, SEL name, IMP imp, const char *types)

参数说明:

cls:被添加方法的类。

name:可以理解为方法名,这个貌似随便起名,比如我们这里叫sayHello2。

imp:实现这个方法的函数。

types:一个定义该函数返回值类型和参数类型的字符串。

接着创建EmptyClass的实例,调用sayHello2,运行,输出Hello,添加方法成功。

#if TARGET_IPHONE_SIMULATOR
#import <objc/objc-runtime.h>
#else
#import <objc/runtime.h>
#import <objc/message.h>
#endif

@interface EmptyClass:NSObject

@end

@implementation EmptyClass

@end

void sayHello(id self, SEL _cmd) {
    NSLog(@"Hello");
}

- (void)addMethod {
    class_addMethod([EmptyClass class], @selector(sayHello2), (IMP)sayHello, "[email protected]:");

    // Test Method
    EmptyClass *instance = [[EmptyClass alloc] init];
    [instance sayHello2];

    [instance release];

}

二、为什么不要重写原有类方法

主要原因如下:

CocoaFramework有很多是用Category实现的,重写之后,会导致在Runtime的时 候,只有一个方法会被执行,而哪个会被执行是undefined。

例如,重写NSString的一个方法base64EncodedString,而其他CocoaFramework的也有可能使用Category来实现这个方法,这样就会导致在Runtime的时候,执行哪个方法是Undefined。

另外,有个地方要注意,那就是Category方法的命名。

通常的明明方式是加一个前缀,例如

-(void)WC_setUpCustomButton;

因为,现在名字并未发生冲突,IOS版本在更新,SDK也在更新,也就是说要尽量保证将来方法的名称也不发生冲突。

三、联合存储实现方式及底层原理解析

动态语言的最大好处,就是灵活性,对于Objective-C来说,能在运行时动态地为类增加方法和实例变量是很多其它语言羡慕不已的能力。现在说说为类增加实例变量用到的技术:联合存储。

一、联合存储的实现方式

下面这段代码实现了为Duck类增加color属性:

Duck+associative.h文件

#import "Duck.h"  

@interface Duck (associative)  

@property (nonatomic, retain) NSString *color;  

@end 

Duck+associative.m文件

#import "Duck+associative.h"
#import <objc/runtime.h>  

@implementation Duck (associative)  

static char colorKey = NULL;  

- (NSString *)color {
    return objc_getAssociatedObject(self, &colorKey);
}  

- (void)setColor:(NSString *)aColor {
    objc_setAssociatedObject(self, &colorKey,
                             aColor,
                             OBJC_ASSOCIATION_RETAIN);
}  

调用举例:

Duck    *smallDuck = [[Duck alloc] init];
smallDuck.color = @"red color";
NSLog(@"duck color:%@",smallDuck.color);
[smallDuck release];  

输出结果:

2013-07-18 19:09:26.578 ObjcRunTime[429:403] duck color:red color  

至此,我们已经成功的为Duck类增加了一个color属性。

四、联合存储的优缺点

1、优点

联合存储的最大的优点,在于它能通过灵活的方式实现为类增加属性。

2、缺点

效率低,使用单条机器指令就可以访问真正的实例变量,但是访问存储在映射表中的值需要多个函数调用,效率问题还是需要注意的。

事实上,目前许多Cocoa类,像NSAttributedString、NSFileManager、NSNotification、NSProcessInfo等都广泛地使用了联合存储。

参考链接:

  1. iOS在运行时为类添加方法
  2. Objective-C通过联合存储为类增加属性及原理解析
  3. iOS - 如何给1个类添加属性
  4. Add variables to an existing class in objective-c
  5. Faking instance variables in Objective-C categories with Associative References
时间: 2024-10-26 19:36:53

iOS类添加方法、属性学习笔记的相关文章

ios runtime 动态向类添加方法

1.定义C函数: void dynamicMethodIMP(id self, SEL _cmd) { NSLog(@"蜗牛也疯狂"); } 2.重写函数+(BOOL)resolveInstanceMethod:(SEL)sel +(BOOL)resolveInstanceMethod:(SEL)sel { class_addMethod([self class], sel, (IMP)dynamicMethodIMP, "[email protected]:");

ios/mac/COCOA系列 -- UIALertVIew 学习笔记

最近在学习ios开发,学习的书籍<ios7 Pragramming cookbook>,做笔记的目的以后方便查看.笔记形式是小例子,将书上的例子书写完整. UIAlertViewClass 的使用场景 1,向用户以一个警告的形式显示信息. 2,让用户确认一些动作 3,让用户输入用户名和密码 4,让用户输入一些文本,这些文本在程序被使用 例1   实现简单显示一些警告信息 新建一个 Single View Application 简单工程,工程名字维AlterView,扩展前缀CB   代码如下

iOS多线程之GCD学习笔记

什么是GCD 1.全称是Grand Central Dispatch,可译为“牛逼的中枢调度器” 2.纯C语言,提供了非常多强大的函数 GCD的优势 GCD是苹果公司为多核的并行运算提出的解决方案 GCD会自动利用更多的CPU内核(比如双核.四核) GCD会自动管理线程的生命周期(创建线程.调度任务.销毁线程) 程序员只需要告诉GCD想要执行什么任务,不需要编写任何线程管理代码 任务和队列 GCD中有2个核心概念 任务:执行什么操作 队列:用来存放任务 GCD的使用就2个步骤,首先确定定制任务(

扩展方法(为那些已经写好不能修改源码的类添加方法)

参考:https://docs.microsoft.com/zh-cn/dotnet/csharp/programming-guide/classes-and-structs/how-to-implement-and-call-a-custom-extension-method 本主题介绍如何实现 .NET Framework 类库 中任意类型的扩展方法,或是你想要扩展的任何其他 .NET 类型. 客户端代码可以通过以下方法使用扩展方法,添加包含这些扩展方法的 DLL 的引用,以及添加 usin

ios FMDB类库的使用 学习笔记

文章摘自:  文顶顶 iOS开发数据库篇-FMDB简单介绍 什么是FMDB FMDB是ios平台的sqlite数据库框架 FMBD以oc的方式封装了sqlite的c语言API FMDB的优点 使用起来更加面向对象,省去了很多麻烦.冗余的c语言代码 比苹果的core Data框架,更加轻量级和灵活 提供了多线程安全的数据库操作方法,有效地防止数据混乱 FMDB的github地址 https://github.com/ccgus/fmdb 核心类 FMDB有三个主要的类 1.FMDatabase 一

C++中class(类)与继承白话学习笔记

1.class(类) class Drink{//定义饮料类 public://public下面的东西可以被外面访问 char* type;//饮料种类 double price;//饮料价格 double volume;//饮料体积 double currentVolume;//饮料剩余体积 bool isEmpty();//判是否喝完:成员函数(member function) void addDrink(double vol);//添加饮料:成员函数 Drink();//初始化函数,用于初

java方法重载学习笔记

java中方法的重载 (1) 方法重载是让类以统一的方式处理不同类型数据的一种手段.多个同名函数同时存在,具有不同的参数个数/类型. 重载Overloading是一个类中多态性的一种表现. (2) java的方法重载,就是在类中可以创建多个方法,它们具有相同的名字,但具有不同的参数和不同的定义. 调用方法时通过传递给它们的不同参数个数和参数类型来决定具体使用哪个方法, 这就是多态性. (3) 重载的时候,方法名要一样,但是参数类型和个数不一样,返回值类型可以相同也可以不相同.无法以返回型别作为重

PHP_获取类的方法/属性

PHP获取当前类名.方法名  __CLASS__ 获取当前类名  __FUNCTION__ 当前函数名(confirm)  __METHOD__ 当前方法名 (bankcard::confirm) __FUNCTION__    函数名称(PHP 4.3.0 新加).自 PHP 5 起本常量返回该函数被定义时的名字(区分大小写).在 PHP 4 中该值总是小写字母的.__CLASS__    类的名称(PHP 4.3.0 新加).自 PHP 5 起本常量返回该类被定义时的名字(区分大小写).在

[ActionScript3.0] 为内建类添加方法

通过使用prototype在继承内建类特性的同时加入新方法 Array.prototype.removeElement = function (item:*):void { var index:int = this.indexOf(item); if(index>-1){ this.splice(index,1); } } var arr:Array = [1,2,3]; arr.removeElement(1); trace(arr);//2,3