1.创建1个对象,这个对象在内存中是如何分配的,
1).子类对象中有自己的属性和所有父类的属性, 2).代码段中的每1个类都有1个叫做isa的指针,这个指针指向它的父类,一直指到NSObject [p1 sayHi]; //假设p1是Person对象, 先根据p1指针找到p1指向的对象,然后根据对象的isa指针找到Person类 搜索Person类中是否有这个sayHi方法 如果有执行如果没有 就根据类的isa指针找父类NSObject 中如果没有就报错,
copy success
2)。在代码段存储类的那块空间是个什么类型的 在代码段中存储类的步骤
a. 先在代码段中创建1个Class对象,Class是Foundation框架中的1个类.这个Class对象就是用来存储类信息的,
b,将类的信息存储在这个Class对象之中: 这个Class对象,至少有3个属性 类名: 存储的这个类的名称。 属性s: 存储的这个类具有哪些属性 方法s: 存储的这个类具有哪些方法, 所以,类是以Class对象的形式存储在代码段的,存储类的这个Class对象 我们也叫做类对象。用来存储类的1个对象 所以,存储类的类对象也有1个叫做isa指针的属性 这个指针指向存储父类的类对象,
- SEL 全称叫做 selector 选择器: SEL 是1个数据类型,所以要在内存中申请空间存储数据SEL其实是1个类。SEL对象是用来存储1个方法的,
2,类是以Class对象的形式存储在代码段之中, 类名:存储的这个类的类名,NSString 还要将方法存储在类对象之中,如何将方法存储在类对象之中, 1).先创建1个SEL对象。 2).将方法的信息存储在这个SEL对象之中, 3).再将这个SEL对象作为类对象的属性,
拿到存储方法的SEL对象 1).因为SEL是1个typedef类型的 在自定义的时候已经加 "*"了, 所以我们在声明SEL指针的时候 不需要加*
2).取到存储方法的SEL对象, SEL s1 = @selector(方法名);
4.调用方法的本质, [p1 sayHi]; 内部的原理: 1). 先拿到存储sayHi方法的SEL对象,也就是拿到存储sayHi方法的SEL数据, SEL消息, 2). 将这个SEL消息发送给p1对象, 3). 这个时候,p1对象接收到这个SEL消息以后 就知道要调用方法 4). 根据对象的isa指针找到存储类的类对象 5). 找到这个类对象以后 在这个类对象中去搜寻是否有和传入的SEL数据相匹配的,如果有 就执行 如果没有再找父类 直到NS0bject OC最重要的1个机制:消息机制, 调用方法的本质其实就是为对象发送SEL消息[p1 sayHi];为p1对象发送1条sayHi消息。
6,手动的为对象发送SEL消息, 1),先得到方法的SEL数据: 2),将这个SEL消息发送给p1对象 调用对象的方法 将SEL数据发送给对象。 -(id)performSelector:(SEL)aSelector; Person *p1=[Person new]; SEL s1 = @selector(sayHi); [p1 performselector:s1]; 与[p1 sayHi]效果是完全一样的.
if ([p1 respondsToSelector:s1]) { [p1 performSelector:s1]; }
copy success
2
3
4
在 Objective-C 中,你是将消息(或者说方法)发送给特定的对象,而不是类。所以当你使用 performSelector:
方法时,实际上是在告诉一个特定的对象去执行与给定选择器关联的方法。
以下面这段代码为例:
Person *p1 = [Person new]; SEL s1 = @selector(sayHi); [p1 performSelector:s1];
copy success
2
3
在这里,你创建了一个 Person
类型的对象 p1
,然后告诉 p1
执行名为 sayHi
的方法。运行时系统会查找 p1
对象(包括它的父类)是否有一个名为 sayHi
的方法,如果找到了,就执行那个方法;如果没有找到,则会抛出异常。
对于你的问题,假设 sayHi
方法在多个类中都存在,例如 Person
类和 Dog
类,并且它们的实现方式可能会有所不同。你如何知道选的是哪个方法呢?答案取决于你向哪个对象发送 sayHi
消息。如果你创建的是 Person
对象并向其发送 sayHi
消息,那么就会调用 Person
类中的 sayHi
方法;如果你创建的是 Dog
对象并向其发送 sayHi
消息,那么就会调用 Dog
类中的 sayHi
方法。
这就是动态方法派发的一个重要特性:实际执行的方法取决于消息接收者(即对象)的类型,而不是选择器。
是的,@selector()
可以接受任何方法名作为参数,无论这个方法在当前上下文中是否存在。然而,如果你试图将一个未知的选择器(代表不存在的方法)用于 performSelector:
或其他需要选择器的方法,那么在运行时将会抛出异常。
例如,以下代码段将会在运行时抛出异常:
Person *p1 = [Person new]; SEL unknownSelector = @selector(methodThatDoesNotExist); [p1 performSelector:unknownSelector];
copy success
2
3
因为 Person
类没有实现 methodThatDoesNotExist
方法,所以当你尝试让 p1
执行这个方法时,程序便会崩溃。
不过,你可以通过 respondsToSelector:
方法进行检查,以避免这种情况:
Person *p1 = [Person new]; SEL unknownSelector = @selector(methodThatDoesNotExist); if ([p1 respondsToSelector:unknownSelector]) { [p1 performSelector:unknownSelector]; } else { NSLog(@"'Person' does not respond to 'methodThatDoesNotExist'"); }
copy success
2
3
4
5
6
7
这样,如果 Person
类没有实现 methodThatDoesNotExist
方法,就不会尝试执行这个方法,从而避免了运行时错误。
请注意,尽管可以使用不存在的方法创建选择器,但在编码时最好避免这种情况,除非你已经掌握了 Objective-C 的动态特性并且明确知道你在做什么。否则,这可能会导致难以调试的运行时错误。
当你需要使用 performSelector:
方法来调用需要参数的方法时,Objective-C 提供了两个额外的方法:performSelector:withObject:
和 performSelector:withObject:withObject:
。这两个方法可以分别传递一个和两个参数。
例如,假设你有一个 Person
类,其中包含一个接受一个 NSString
参数的 setName:
方法:
@class Person : NSObject - (void)setName:(NSString *)name; @end
copy success
2
3
你可以使用 performSelector:withObject:
来调用这个方法:
Person *p1 = [[Person alloc] init]; [p1 performSelector:@selector(setName:) withObject:@"John"];
copy success
2
如果你的方法接受两个参数,比如 setFirstName:lastName:
,你可以使用 performSelector:withObject:withObject:
方法:
[p1 performSelector:@selector(setFirstName:lastName:) withObject:@"John" withObject:@"Doe"];
copy success
请注意,由于 performSelector:withObject:
和 performSelector:withObject:withObject:
方法的限制,它们只能接受对象类型的参数(即所有继承自 NSObject
的类的实例)。对于基本数据类型(如 int、double 等),你需要将它们装箱到相应的 NSNumber
对象中;对于 C 字符串,你需要把它们转换为 NSString
对象。
OC的对象如果要为属性赋值或者取值 就要调用对应的getter或者setter.
2.使用点语法来访问对象的属性,
语法: 对象名,去掉下划线的属性名; p1.name = @"jack"; 这个时候就会将@"jack"赋值给p1对象的 name属性, NSString *name = p1.name; 把p1对象的name属性的值取出来.
copy success
3.点语法的原理
p1.age = 18; 这句话的本质并不是把18直接赋值给p1对象的_age属性, 点语法在编译器编译的时候,其实会将点语法转换为调用setter、getter的代码, 1),当使用点语法赋值的时候,这个时候编译器会将点语法转换为调用setter方法的代码 对象名.去掉下划线的属性名 = 数据; 转换为: [对象名 set去掉下划线的属性名首字母大写:数据]; p1.age = 10; [p1 setAge:10]; 2),当使用点语法取值的时候,这个时候编译器会将点语法转换为调用getter方法的代码 对象名.去掉下划线的属性名; 转换为: [对象名 去掉下划线的属性名]; int age = p1.age; int age = [p1 age];
copy success
4.注意,
1),在getter和setter中慎用点语法,因为有可能会造成无限递归 而程序崩溃, 2)点语法在编译器编译的时候 会转换为调用setter getter方法的代码, p1.name = jack" [p1 setName:@"jack"] NSString *name = pl.name; NSString *name = [p1 name]; 如果我们的setter方法和getter方法名不符合规范 那么点语法就会出问题,
copy success
@property
1).作用: 自动生成getter、setter方法的声明, 因为是生成方法的声明,所以应该写在@interface类的声明之中, 2).语法: @property 数据类型 名称; @property int age; 3).原理: 编译器在编译的时候,会根据@property生成getter和setter方法的声明, @property 数据类型 名称; 生成为: - (void)set首字母大写的名称:(数据类型)名称; - (数据类型)名称; @property int age; - (void)setAge:(int)age; - (int)age;
copy success
@synthesize
1).作用:自动生成getter、setter方法的实现,所以,应该写在类的实现之中, 2).语法: @synthesize @property名称; @interface Person : Nsobject { int _age; } @property int age; @end @implmentation Person @synthesize age; @end a.生成1个真私有的属性,属性的类型和@synthesize对应的@property类型一致 属性的名字和@synthesize对应的@property名字一致, b.自动生成setter方法的实现. 实现的方式:将参数直接赋值给自动生成的那个私有属性(非接口里面带下划线的属性),并且没有做任何的逻辑验证 c.自动生成getter方法的实现. 实现的方式:将生成的私有属性的值返回 3.希望@synthesize不要去自动生成私有属性了。getter setter的实现中操作我们已经写好的属性就可以了, 语法: @synthesize @property名称 = 已经存在的属性名; @synthesize age =_age; 1),不会再去生成私有属性. 2).直接生成setter getter的实现 setter的实现:把参数的值直接赋值给指定的属性, gettter的实现:直接返回指定的属性的值,
copy success
批量声明
1),如果多个@property的类型一致,可以批量声明, @property float height,weight; 2)@synthesize也可以批量声明, @synthesize name = _name,age = _age,weight =_weight,height = _height;
copy success
TIP
@property只是生成getter setter 的声明 @synthesize是生成gettersetter 的实现:
这种写法是Xcode4.4之前的写法。从Xcode4.4以后.Xcode对@property做了1个增强
2.@property增强 只需要写1个@property 编译器就会自动 1)生成私有属性。 2).生成getter setter的声明, 3).生成getter setter的实现, @property NSString *name; 做的事情 1).自动的生成1个私有属性,属性的类型和@property类型一致 属性的名称和@property的名称一致 属性的名称自动的加1个下划线, 2).自动的生成这个属性的getter setter方法的声明 3).自动的生成这个属性的getter setter方法的实现
setter的实现:直接将参数的值赋值给自动生成的私有属性, getter的实现:直接返回生成的私有属性的值。
NSObject.
是OC中所有类的基类,根据LSP NSObject指针就可以指向任意的OC对象,所以NSObiect指针是1个万能指针,可以执行任意的OC对象,
缺点:如果要调用指向的子类对象的独有的方法,就必须要做类型转换,
id指针 是1个万能指针,可以指向任意的0C对象,
1). id是1个typedef自定义类型 在定义的时候已经加了* 所以声明id指针的时候不需要再加*了。 2)id指针是1个万能指针,任意的OC对象都可以指.
copy success
3.NSObject和id的异同,
相同点:万能指针 都可以执行任意的0C对象, 不同点: 通过NS0bject指针去调用对象的方法的时候,编译器会做编译检查, 通过id类型的指针去调用对象的方法的时候,编译器直接通过,无论你调用什么方法, 注意: id指针只能调用对象的方法 不能使用点语法,如果使用点语法就会直接报编译错误 。
copy success