iOS程序员面试分类模拟5_第1页
iOS程序员面试分类模拟5_第2页
iOS程序员面试分类模拟5_第3页
iOS程序员面试分类模拟5_第4页
iOS程序员面试分类模拟5_第5页
已阅读5页,还剩11页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

iOS程序员面试分类模拟5简答题1.

什么是目标-动作机制?正确答案:目标-动作(target-action)机制是一种设计模式,用于一个对象在某个事件发生时向另一个对象发送消息。消息中要包含一个(江南博哥)selector,用于确定要触发的方法,该方法即该机制中的动作。还要包含一个target(目标),表示消息的接收者,例如一个控件,或者更为常见的是它的单元,以插座变量的形式保有其动作消息的目标。

目标-动作机制符合软件开发中“高内聚,低耦合”的设计目标,降低模块间的耦合度,同时增强了模块内部的聚合度。目标一动作机制主要用于MVC设计模式中V到C的通信,通过该机制,充当V的组件只要在UI事件发生时通知C即可,之后的逻辑处理全交由C去进一步处理。

典型的例子是UIButton的单击事件和方法的绑定,当按钮事件发生时,会触发接收者对于该事件所绑定的方法。这里的UIButton按钮即MVC中的V组件,通过目标一动作机制绑定的selector方法即属于C中的后续逻辑处理部分。

[buttonaddTarget:selfaction:@selector(click:)forControlEvents:UIControlEventTouchUpInside];

2.

如何打印一个类中所有的实例变量?正确答案:Objective-C中的类是由Class类型来表示的,而Class是一个objc_clas类型的结构体,它包含了实例变量列表(objc_ivar_list)、方法列表(objc_method_list)和协议列表(objc_protocol_list)。开发者可以通过runtime提供的函数来操作这些列表,获取成员变量列表的函数如下:

Ivar*class_copyIvarList(Classcls,unsignedint*outCount)

这个函数返回一个包含所有实例变量的数组,但是父类中的实例变量不会被返回。示例代码如下:

/*新建Person类,为其添加属性*/

#import<Foundation/Foundation.h>

@interfacePerson:NSObject

@properly(nonatomic,strong)NSString*name;

@property(nonatomic,assign)NSIntegerage;

@end

#import"Person.h"

@interfacePerson()

@property(nonatomic,strong)NSString*sex;

@end

@implementationPerson

-(instancetype)init{

if(self=[superinit]){

self.sex=@"male";

}

returnself;

}

@end

/*在控制器中获取其实例变量列表并打印*/

Person*aperson=[[Personalloc]init];

aperson.age=20;

=@"sam";

unsignedintcount=0;

/*用一个字典装实例变量的名称和值*/

NSMutableDictionary*dict=[NSMutableDictionarydictionary];

Ivar*list=class_copyIvarList([apersonclass].&count);

for(inti=0;i<count;i++){

NSString*ivarName=INSStringstringWithUTF8String:ivar_getName(1ist[i])];

idivarValue=[apersonvalueForKey:ivarName];

if(ivarValue){

dict[ivarName]=ivarValue;

}else{

dict[ivarName]=@"";

}

}

/*打印*/

for(NSString*ivarNameindict.allKeys){

NSLog(@"ivarName:%@,ivarValue:%@",ivarName,dict[ivarName]);

}

程序的打印结果如下:

2016-11-0419:38:19.56001[5774:408980]ivarName:_name,ivarValue:sam

2016-11-0419:38:19.56001[5774:408980]ivarName:_age,ivarValue:20

2016-11-0419:38:19.56101[5774:408980]ivarName:_sex,ivarValue:male

总结runtime函数的命名和作用,可以很容易发现以下一些规律:

1)objc开头的函数一般都是高于类的操作,例如注册类、添加类等。

2)class开头的函数是针对objc_class结构体的内部进行操作,例如示例中的查看实例变量列表等。

3)object开头的函数主要是对对象进行修改,例如修改ivar的值、调用某个method等。

4)ivar、property和method开头的函数主要是对实例变量、属性和方法的操作。

3.

如何使用runtime动态添加一个类?正确答案:runtime之所以非常强大,很关键的一点就是它能够动态地创建一个全新的类或对象。在runtime.h文件中可以查到动态创建一个类所涉及的所有函数。

/*创建一个新类或元类*/

objc_allocateClassPair(Classsuperclass,constchar*name,size_textraBytes)

/*注册一个通过objc_allocateClassPair方法创建的类*/

objc_registerClassPair(Classcls)

/*销毁一个类及其元类*/

objc_disposeClassPair(Classcls)

上面3个函数的作用见表。动态创建类所涉及的3个函数函数名作用objc_allocateClassPair函数它的作用是创建一个新类或元类。如果开发者想让这个类成为基类,那么参数superclass指定为nil。参数extraBytes是分配给类和元类对象尾部的索引ivars的字节数,通常指定为0objc_registerClassPair函数当创建完新类后,需要调用这个方法来注册这个类,之后这个类才可以在程序中使用objc_disposeClassPair函数用于销毁一个类及其元类。需要注意的一点是,如果程序运行中还存在类或其子类的实例,那么就不能调用该方法

那么,如何运用上述3个函数动态地添加一个类呢?示例代码如下:

/*创建一个新类myClass*/

ClassmyClass=objc_allocateClassPair([NSObjectclass],"myClass",0);

/*添加ivar*/

//@encode(aType):返回该类型的C字符串

class_addIvar(myClass,"_address",sizeof(NSString*),log2(sizeof(NSString*)),@encode(NSString*));

class_addIvar(myClass,"_age",sizeof(NSUInteger),log2(sizeof(NSUInteger)),@encode(NSUInteger));

/*注册类*/

objc_registerClassPair(myClass);

/*创建实例*/

idobject=[[myClassalloc]init];

/*为ivar设置值*/

[objectsetValue:@"china"forKey:@"address"];

[objectsetValue:@20forKey:@"age"];

NSLog(@"address=%@,age=%@",[objectvalueForKey:@"address"],[objectvalueForKey:@"age"]);

/*当类或者它的子类的实例还存在,则不能调用objc_disposeClassPair方法*/

object=nil;

/*销毁*/

objc_disposeClassPair(myClass);

程序的打印结果如下:

2016-11-0219:32:39.61501[67782:2681508]address=china,age=20

这样就通过运行时动态创建了一个继承自NSObject的myClass类,并为这个新类添加了address和age两个成员变量。特别需要注意的是,添加成员变量的方法class_addIva必须要在objc_allocateClassPair和objc_registerClassPair之间调用才行,这里涉及Objective-C中类的成员变量的偏移量,如果在类注册之后再调用class_addIva方法,那么会破坏原来类成员变量正确的偏移量,导致的后果就是会获取到错误的成员变量。

4.

如何在Category中增加属性(关联对象)?正确答案:在实际开发中,如果为Category添加一个属性,那么系统将不会为这个属性设置访问器方法,也就是setter和getter方法。这时候可以使用runtime提供的关联对象方法,动态地为该属性实现访问器方法。

开发者可以将关联对象想象成一个Objective-C对象,这个对象通过一个预先设置好的key连接到类的一个实例上。runtime提供了如下方法让一个对象连接到其他对象。

voidobjc_setAssociatedObject(idobject,constvoid*key,

idvalue,objc_AssociationPolicypoliey)

参数object是将要被关联的对象。参数key是一个void指针。参数value是关联对象,它是id类型。参数policy是指定一个内存管理策略来处理关联对象。如果指定的策略OBJC_ASSOCIATION_ASSIGN,那么被关联对象释放时,关联对象不会被释放,而如果指定的OBJC_ASSOCIATION_RETAIN或OBJC_ASSOCIATION_COPY,那么关联对象就会被释放。另外,还有OBJC_ASSOCIATION_RETAIN_NONATOMIC和OBJC_ASSOCIATIO_COPY_NONATOMIC两种策略,当需要在多个线程中处理访问关联对象的多线程代码时,就会变得非常有用。

除此之外,runtime还提供了移除关联对象的方法:

voidobjc_removeAssociatedObjects(idobject)

可以使用这个方法移除所有和参数object关联的对象,或者使用objc_setAssociatedObject函数将key指定的关联对象设置为nil。

下面的示例代码演示了如何为Person的Category添加一个属性。

/*为Person类的Category添加address属性*/

#import"Person.h"

@interfacePerson(Cate)

@property(nonatomic,strong)NSString*address;

@end

/*在.m文件中为address属性实现访问器方法*/

#import"Person+Cate.h"

#import<obje/objc-runtime.h>

@implementationPerson(Cate)

-(id)address{

idvalue=objc_getAssociatedObject(se!f,"address");

returnvalue;

}

-(void)setAddress:(NSString*)address{

objc_setAssociatedObject(self,"address",address,OBJC_ASSOCIATION_RETAIN);

}

@end

/*在控制器中打印属性值*/

Person*aperson=[[Personalloc]init];

aperson.address=@"China";

NSLog(@"address=%@",aperson.address);

程序的打印结果如下:

2016-11-0319:17:40.94901[2756:152639]aaddress=China

结果说明已经成功地在Category中为类添加了一个新的属性,并且能够正常地使用这个属性。事实上,关联对象是使用哈希表实现的,将一个类映射到一张哈希表上,然后根据key找到关联对象,所以严格来说,关联对象和被关联对象没有任何关系,它不是存储在对象的内部。

5.

如何理解消息传递机制?正确答案:对Objective-C对象调用方法的操作通常称为“消息传递”。在Objective-C中,如果向某对象传递消息,那么就会使用动态绑定机制来决定需要调用的方法。在底层,所有方法都是普通的C语言函数,然而对象收到消息之后,究竟该调用哪个方法则完全由runtime来决定,有时甚至可以在运行期改变方法的实现。

在代码中给对象发送消息可以这样来编写:

[receivermessageName:parameter];

消息的接收者(receiver)和参数(parameter)合起来称为“消息”(message)。在编译阶段,会将上面的代码转换成C语言函数调用,所调用的函数是消息传递机制中的核心函数,叫作objc_megSend,其在objc/message.h文件下的定义如下:

voidobjc_msgSend(void/*idself,SELop,...*/)

objc_msgSend函数将消息接收者和方法名作为其基础参数。其中,参数self代表消息接收者,参数SEL代表方法名(selector,又称选择器)。每个类中的方法列表(methodLists)类似于一张表格,其中的指针都会指向方法的实现,而方法名是查表时所用的键。objc_msgSend函数正是通过这张表格来寻找应该执行的方法并跳转至其实现的。

objc_msgSend函数会根据接收者和方法来调用适当的方法。基本流程如下:

1)objc_msgSend函数通过isa指针在接收者所属的类中搜寻方法缓存列表(cache)和方法列表,如果能找到与方法名相符合的方法,那么就跳转至其实现代码。

2)若是找不到,那么就会通过super_class指针沿着类的继承体系继续向上查找,如果能够找到合适的方法,那么就会跳转。

3)如果上面两步都无法找到相符的方法,那么就会执行消息转发(messageforwarding)机制。

6.

什么是SEL?正确答案:SEL又称选择器,表示的是一个方法的selector的指针。在很多方法名中都可以看到,例如UIControl.h中事件的监听方法:

-(void)addTarget:(nullableid)targetaction:(SEL)actionforControlEvents:(UIControlEvents)controlEvents;

其中,参数action就是SEL类型。SEL的定义如下:

typedefstructobjc_selector*SEL;

方法的selector用于表示运行时方法的名字。Objective-C在编译时,会根据每个方法的名字、参数列表,生成一个唯一的整型标识,这个标识就是SEL。正因为其具有唯一性,所以在Objective-C的同一个类中,不能存在两个同名的方法,即使参数类型不同也不行。

开发者可以在运行时添加新的selector,也可以在运行时获取已存在的selector。可以通过下面3种方法来获取SEL。

/*在运行时注册一个方法,返回一个SEL指针*/

SELsel_registerName(constchar*str)

/*编译器提供的方法*/

@selector(selector)

/*通过字符串获取SEL*/

NSSelectorFromString(NSString*aSelectorName);

事实上,工程中所有的SEL会组成一个Set集合,Set的特点就是具有唯一性,因此SEL也是唯一的。如果想要查找某个方法,那么只需要找到这个方法所对应的SEL就可以了,SEL实际上就是根据方法名Hash转换的一个字符串。

7.

什么是IMP?正确答案:和SEL一样,IMP实际上也是个函数指针,它指向方法实现的首地址,可以把它理解为方法的具体实现。其定义如下:

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

前面讲到可以通过SEL指针查找方法,实际上就是查找方法的IMP。由于每个方法对应唯一的SEL,所以可以通过SEL方便快速准确地获取它所对应的IMP。取得IMP之后,就可以像调用普通的C语言函数一样来使用这个函数指针了。

在objc/runtime.h中还定义了用以表示方法的结构体。

typedefstructobjc_method*Method;

structobjc_method{

SELmethod_name

OBJC2_UNAVAILABLE;

//方法名

char*method_types

OBJC2_UNAVAILABLE;

IMPmethod_imp

OBJC2_UNAVAILABLE;

//方法实现

}

可以看到结构体objc_method包含了一个SEL和IMP,实际上它相当于在SEL和IMP之间作了一个映射。

8.

如何理解消息转发机制?正确答案:当一个对象能处理一个消息时,就会执行正常的消息传递步骤。如果一个对象无法处理这个消息,那么就会进入消息转发。默认情况下,如果是以[objectmessage]的方式调用方法,当object无法响应message时,那么编译器会报错。如果是以performSelector的形式来调用,那么编译器在编译时还无法确定类中到底会不会有这个方法的实现。如果没有该方法的实现,那么就会导致程序崩溃。示例代码如下:

/*person类中并不存在eat方法*/

Person*aperson=[[Personalloc]init];

[apersonperformSelector:@selector(eat)];

控制台打印结果如下:

[Personeat]:unrecognizedselectorsenttoinstance0x600000029800

上述这段异常信息实际上是由NSObject的doesNotRecognizeSelector:方法所抛出的,此异常信息表明Person类的实例对象无法响应eat方法。在示例中,消息转发过程以程序的崩溃而结束,但是开发者可以利用runtime,在消息转发过程中采取一些措施,而避免程序的崩溃。当然,先要理解消息转发机制的原理。消息转发机制基本分为3个阶段。

1.动态方法解析

对象在收到无法解读的消息后,将调用其所属类的下列类方法:

+(BOOL)resolveInstanceMethod:(SEL)sel

或者

+(BOOL)resolveClassMethod:(SEL)sel

这两个方法的参数就是那个未知的方法,返回值都是Boolean类型,表示这个类能否动态地添加一个新的方法来处理这条消息。在这里可以新增一个处理该消息的方法。

使用这种方法的前提是:相关的方法的实现代码已经写好,只等着运行期动态插入类的MethodList中就可以了。此方案常用来实现@dynamic属性,示例代码如下:

/*在控制器中调用Person类的实例方法eat,但是eat方法没有实现*/

Person*aperson=[[Personalloc]init];

[apersonperformSelector:@selector(eat)];

/*在Person类中为eat动态添加方法的实现*/

+(BOOL)resolveInstanceMethod:(SEL)sel{

NSString*str=NSStringFromSelector(sel);

if([strisEqualToString:@"eat"]){

IMPimp=method_getImplementation(class_getInstanceMethod(self,@selector(breakfast)));

class_addMethod(self,@selector(eat),imp,"");

}

return[superresolveInstanceMethod:sel];

}

-(void)breakfast{

NSLog(@"我吃了早餐了");

}

程序的打印结果如下所示:

2016-11-0518:25:51.89701[11777:779796]我吃了早餐了

在示例代码中,先将消息转化为字符串,然后检测其是否能够表示eat方法。若是eat方法,则为其设置方法的实现。程序的打印结果表明,已经成功地拦截了消息转发并对未知消息(eat)进行了处理。

2.备用接收者

如果在上一步中无法处理消息,那么当前接收者还有第二次机会来处理未知消息,在这一步,runtime会调用如下方法:

-(id)forwardingTargetForSelector:(SEL)aSelector

方法参数代表未知消息,如果当前接收者能找到备用接收者,那么将其返回;如果找不到,那么就返回nil。通过此方法可以模拟出“多重继承”的一些特性。在一个对象内部,可能还有一系列其他的对象,该对象可通过此方法将能够处理未知消息的相关内部对象返回,这样在外界看来,好像是该对象亲自处理了这些消息。示例代码如下:

/*新建一个PersonHelper类*/

@implementationPersonHelper

@interfacePersonHelper:NSObject

-(void)eat;

@end

-(void)eat{

NSLog(@"别人帮我吃东西");

}

@end

/*在Person.m中设置PersonHelper类的实例为属性*/

@interfacePerson()

@property(nonatomic,strong)PersonHelper*helper;

@end

@implementationPerson

-(instancetype)init{

if(self=[superinit]){

_helper=[[PersonHelperalloc]init];

}

returnself;

}

/*实现forwardingTargetForSelector:方法*/

-(id)forwardingTargetForSelector:(SEL)aSelector{

NSString*str=NSStringFromSelector(aSelector);

if([strisEqualToString:@"eat"]){

return_helper;

}

return[superforwardingTargetForSelector:aSelector];

}

@end

/*在控制器中执行eat方法*/

Person*aperson=[[Personalloc]init];

[apersonperformSelector:@selector(eat)];

以上程序的打印结果如下:

2016-11-0518:45:25.87001[11892:788458]别人帮我吃东西

程序打印结果表明,已经成功地在第二步中将消息转发给其他对象来执行了。这里需要注意,开发者无法操作通过这一步所转发的消息。若是想在发送给备用接收者之前先修改消息内容,那就必须采用完整的消息转发机制来操作。

3.完整的消息转发机制

如果以上两步都无法处理未知消息,那么唯一能做的就是启用完整的消息转发机制。此时会调用如下方法:

-(void)forwardInvocation:(NSInvocation*)anInvocation

这里要创建NSInvocation对象,把与尚未处理的那条消息有关的全部细节都封装于其中。此对象包含选择子、目标及参数。在触发NSInvocation对象时,消息派发系统将消息指派给目标对象。当然,从这个角度看来,这一方法与第二步中的备用接收者的实现效果相等。但是事实上可以在触发消息前,先以某种方式改变消息内容,例如追加另外一个参数,或者改变消息名称等。此外,若发现某个消息不应由本类处理,则应调用父类同名方法,以便继承体系中的每个类都有机会处理此请求。

在使用forwardInvocation:方法前,必须重写以下方法:

-(NSMethodSignature*)methodsignatureForSelector:(SEL)aSelector

消息转发机制使用从这个方法中获取的信息来创建NSInvocation对象。因此,开发者必须重写这个方法,为未知消息提供一个合适的方法签名。示例代码如下:

/*在Person.m中实现完整的消息转发*/

-(NSMethodSignature*)methodSignatureForSelector:(SEL)aSelector{

NSMethodSignature*signature=[supermethodSignatureForSelector:aSelector];

if(!signamre&&[_helpermethodSignatureForSelector:aSelector]){

signature=[_helpermethodSignatureForSelector:aSelector];

}

returnsignature;

}

-(void)forwardInvocation:(NSInvocation*)anInvocation{

if([_helperrespondsToSelector:anInvocation.selector]){

[anInvocationinvokeWithTarget:_helper];

}

}

以上程序的打印结果如下:

2016-11-0519:08:13.46501[11951:796216]别人帮我吃东西

默认情况下,NSObject的forwardInvocation:方法实现只是简单调用了doesNotRecognizeSelector:方法,它不会转发任何消息。从某种意义上讲,forwardInvocation:方法类似一个通知中心,可以将所有未知消息都派发出去。通过runtime的消息转发机制,开发者可以为程序动态地增加很多行为,这也是丽试中常考的知识,t量。

9.

isKindOfClass和isMemberOfClass有什么区别与联系?正确答案:isKindOfClass和isMemberOfClass都是Objective-C语言的内省特性方法,用于实现动态类型识别(判断某个对象是否属于某个动态类型)。但两者的类型判定深度不同。

isKindOfClass的判“真”要求相对宽松,它是判断某个对象是否是Class类型的实例或其子类的实例。

isMemberOfClass的判“真”要求相对更高,比isKindOfClass严格的是,isMemberOfClass只判断某个对象是否是Class类型的实例,不放宽到其子类。

例如:Dog类继承自Animal类,对于一个Dog类型的实例对象dog,[dogisKindOfClass:[Animalclass]]为真,而[dogisMemberOfClass:[Animalclass]]为假。

/*Dog类继承自父类Animal*/

Dog*dog=[[Dogalloc]init];

[dogisKindOfClass:[Dogclass]];

//true

[dogisKindOfClass:[Animalclass]];

//true

[dogisMemberOfClass:[Dogclass]];//true

[dogisMemberOfClass:[Animalclass]];//false

10.

Objective-C有私有方法吗?有私有变量吗?正确答案:Objective-C是否有私有方法和私有变量关键要看私有的定义。私有主要指通过类的封装性,将不希望让外界看到的方法或属性隐藏在类内部,只有该类可以在内部访问,外部不可见不可访问。

表面上看,Objective-C中是可以实现私有的变量和方法的,即将它们隐藏不暴露在头文件中,不可以显式地直接访问,但是Objective-C中这种私有并不是绝对的私有,例如即使将变量和方法隐藏在.m实现文件中,开发者仍然可以利用KVC或runtime运行时机制强行访问没有暴露在头文件的变量或方法。

Objective-C中实现变量和方法“私有”的方式主要有两种。

1)在类的头文件中声明私有变量。

#import<Foundation/Foundation.h>

@interfaceTest:NSObject{

/*头文件中定义私有变量,默认为@protected*/

@private

NSString*major;

}

@end

2)在.m实现文件头部的类扩展区域定义私有属性或方法,其中方法可不用声明,直接在实现文件中实现即可,只要不在头文件声明的方法都对外不可见。

#import"Test.h"

@interfaceTest(){

/*类扩展区域定义私有变量,默认就是@private*/

intage;

}

/*类扩展区域定义私有属性*/

@property(nonatomic,copy)NSString*name;

/*类扩展区域定义私有实例方法(可省略声明,类方法的作用主要就是提供对外接口的,所以一般不会定义为私有)*/

-(void)test;

@end

@implementationTest

/*私有实例方法*/

-(void)test{

NSLog(@"这是个私有实例方法!");

}

@end

利用KVC和runtime暴力访问私有属性和变量

KVC访问变量不受私有权限的限制,访问代码如下:

#import"Test.h"

#import<objc/runtime.h>

...

Test*test=[[Testalloc]ink];

/*1.KVO暴力访问私有属性和私有变量*/

[testsetValue:@"albert"forKeyPath:@"name"];

NSString*pname=[testvalueForKey:@"name"];

[testsetValue:@"mathmetics"forKeyPath:@"major"];

NSString*pmajor=[testvalueForKey:@"major"];

NSLog(@"pname:%@pmajor:%@",pname,pmajor);

程序的运行结果为:

2017-04-0211:58:56.255723CommandLine[99973:3239125]pname:albertpmajor:mathmetics

运行时可以使用class_copyIvarList函数获取类对象的Ivar变量列表,然后可使用object_getIvar和object_setIvar运行时函数对变量进行暴力访问。

#import"Test.h"

#import<objc/runtime.h>

...

Test*test=[[Testalloc]init];

/*2.运行时暴力访问私有属性和私有变量(ARC)*/

/*获取实例变量列表*/

unsignedintcount=0;

Ivar*members=class_copyIvarList([Testclass],&count);

/*打印所有的变量名及其类型*/

for(inti=0;i<count;i++){

constchar*memberName=ivar_getName(members[i]);

constchar*memberType=ivar_getTypeEncoding(members[i]);

NSLog(@"name:%stype:%s",memberName,memberType);

}

/*访问私有属性和变量*/

Ivarvarname=members[0];

Ivarvarmajor=members[1];

object_setIvar(test,varname,@"albert");

object_setIvar(test,varmajor,@"mathmetics");

NSString*name=object_getIvar(test,varname);

NSString*major=object_getIvar(test,varmajor);

NSLog(@"pname:%@",name);

NSLog(@"pmajor:%@",major);

/*要手动释放*/

free(members);

程序的运行结果为:

2017-04-0212:07:22.105758CommandLine[189:3242353]name:majortype:@"NSString"

2017-04-0212:07:22.105930CommandLine[189:3242353]name:_nametype:@"NSString"

2017-04-0212:07:22.106156CommandLine[189:3242353]pname:albert

2017-04-0212:07:22.106221CommandLine[189:3242353]pmajor:mathmetics

Runtime暴力访问对象私有方法

和访问私有变量类似,这里使用class_copyMethodList运行时函数获取类对象中的方法列表,然后使用performSelector函数执行某个方法。这里只展示了实例方法的访问,类方法的访问也类似,另外还可以使用class_addMethod运行时函数往类对象中强行添加新的方法,具体见MethodSwizzling部分。

#import"Test.h"

#import<objc/runtime.h>

...

Test*test=[[Testalloc]init];

/*运行时暴力访问私有方法*/

/*获取类对象方法列表*/

unsignedintcount=0:

Method*methods=class_copyMethodList([Testclass],&count);

/*获取第一个方法的方法名*/

SELsel=method_getName(methods[0]);

/*执行该方法*/

[testperformSelector:sel];

11.

在runtime中类与对象如何表示?正确答案:在runtime库中,对象是用C语言中的结构体表示,而方法用C语言中的函数来实现,另外也加入了一些额外的特性。这些结构体和函数被Runtime函数封装后,开发者就可以利用运行时特性在程序运行阶段动态地创建、查看、修改类、对象和它们的方法。在iOS的SDK中,文件夹usr/include/objc下的文件基本都是和运行时相关的文件,其中使用的函数主要定义在message.h和runtime.h两个文件中。在这两个文件中,包含了运行时对象结构体的描述和对运行时进行操作的函数。

1.类(Class)

在runtime中,Objective-C中的类是由Class类型来表示的,通过objc/objc.h可以查看到Class类型实际上是指向objc_class结构的指针。它的定义如下:

///AnopaquetypethatrepresentsallObjective-Cclass.

typedefstructobjc_class*Class;

通过查看objc/runtime.h文件,可以看到objc_class结构体的定义如下:

structobjc_class{

Classisa

OBJC_ISA_AVAILABILITY;

#if!__OBJC2__

Classsuper_classOBJC2_UNAVAILABLE;

constchar*name

OBJC2_UNAVAILABLE;

longversion

OBJC2_UNAVAILABLE;

longinfo

OBJC2_UNAVAILABLE;

longinstance_size

OBJ

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论