p.age=10;
[p setAge:10];
int age=p.age;
int age=[p age];
{
//这行代码会引起死循环
self.age=age;
_age = age;
}
- (int)age
{
//这行代码会引起死循环
return self.age;
}
二.成员变量的作用域:
访问修饰符:
@public:在任何地方都能直接访问对象的成员变量
@private:只能在当前类的对象方法中直接访问(@implementation中默认是@private)
@protected:可以在当前类及其子类的对象方法中直接访问(@interface中默认就是@protected)
@package:只要处在同一个框架中,就能访问对象的成员变量
三.@property和@synthesize:
@property
1.用在@interface中
2.用来自动生成serter和getter的声明
3.用@property int age;就可以代替下面的两行
- (void)setAge:(int)age;
- (int)age;
4.从Xcode4.4版本后 @property就独揽了 @synthesize的功能,可以同时生成setter和getter的声明和实现,默认情况下会访问下划线开头的成员变量
@synthesize:
1.用在@implementation中
2.用来自动生成setter和getter的实现
3. @synthesize age = _age;就可以代替
- (void)setAge:(int)age
{
_age = age;
}
- (int)age
{
return _age;
}
@synthesize:的细节
@synthesize age = _age;
geter和setter实现中会访问成员变量_age;
如果成员变量_age不存在,会自动生成一个@private的成员变量_age
@synthesize age;
setter和getter实现中会访问成员变量age
如果成员变量age不存在,就会自动生成一个@private的成员变量age
手动实现
若手动实现了setter方法,编译器就只会自动生成getter方法
若手动实现了getter方法,编译器就只会生成setter方法
若同时手动实现了getter方法和setter方法,编译器就不会自动生成不存在的成员变量
id类型
// id 为万能指针,指向\操作任何的OC对象
id d = [Person new];
构造方法:
1.构造方法是用来初始化对象的方法,是哥对象方法,用-开头
2.重写构造方法的目的:为了让对象创建出来,成员变量就会有一些固定的值
重写构造方法的注意点:
1.先调用父类的构造方法([super init])
2.在进行子类内部成员变量的初始化
完整的创建一个可用的对象
1.分配存储空间 调用 +alloc 方法
2.初始化 -init
指定义构造方法
自定义构造方法的规范
1.一定是对象方法 ,一定以 - 开头
2. 返回值一般是id类型
3.方法名一般以initwith开头
例子:
// 父类的属性交给父类的方法处理,子类方法处理子类自己的属性
- (id)initWithName:(NSString *)name andAge:(int)age andNo:(int)no
{
// 将name,age传递到父类方法中进行初始化
if(self = [super initWithName:name andAge:age])
{
_no = no;
}
return self;
}
分类:可以给某一个类扩充一些方法(不修改原来类的代码)
声明
@interface 类名(分类名称)
{
方法声明
}
@end
实现
@implementation 类名 (分类名称)
{
方法实现
}
@end
分类的使用注意
1.分类只能增加方法,不能增加成员变量
2.分类方法实现中可以访问原来类中的成员变量
3.分类可以重新实现原来类中的方法,但是会覆盖掉原来类的方法,会导致原来的方法失效
4. 方法调用的优先级 分类(最后参与编译的父类优先) -> 原来类 ->父类
类的本质:
类本身也使一个对象,是Class类型的对象,简称类对象
Class类型的定义
typedef struct objc class *Class
类名就代表着类对象,每个类只有一个对象
获取类对象的2种方式
Class c = [Person class];类方法
或者
Person *p = [Person new];
Class c2 = [p class];
类对象调用类方法
Class c = [Person class];
Person *p2 = [c new];
类加载器
加载(类和分类的+load方法都会调用)
当程序一启动的时候就会加载一次项目中所有的类,类加载完毕的时候调用类的+load方法,这个方法是一个类方法,并且先加载父类调用父类的的load方法
初始化(分类有对应的+initialize方法,只会调用分类的+initialize方法)
当第一次使用这个类的时候就会调用一次类的+initialize方法,先调用父类的+initialize方法
1. 当程序启动的时候就会加载项目中所有的类和分类 ,而且加载后会调用每个类和分类的+load方法,只会调用一次
2. 当第一次使用某个类时,就会调用当前类的+initialize方法
3.先加载父类,再加载子类(先调用父类的+load方法,再调用子类的+load方法)
先初始化父类,再初始化子类(先调用父类的+initialize方法,再调用子类的+initialize方法)
description方法:
1. -description 方法
使用NSLog和%@输出某个对象时,会调用对象的-description方法,并拿到返回值进行输出
默认情况下,利用NSLog和%@输出对象时,结果是:<类名:内存地址>
1.会调用对象p的-description方法
2.拿到-description方法的返回值(NSString *)显示到屏幕上
3.-description方法默认返回的是“类名+内存地址”
2.+description方法
使用NSLog和%@输出某个类对象时,会调用类对象的+description方法,并拿到返回值进行输出
// 1.会调用类的+description方法
// 2.拿到+description方法的返回值(NSString *)显示到屏幕上
Class c = [Person class];
NSLog(@"%@",c);
3.修改NSLog默认输出
重写-description方法或者+description方法即可
4.死循环陷阱
如果在-description方法中使用NSLog打印self;
// 输出方法名称
NSLog(@"%s\n",__func__);
// 输出行号
NSLog(@"%d",__LINE__);
// 输出源文件名称
printf("%s\n",__FILE__);
Person *p = [[Person alloc]init];
//指针变量地址
NSLog(@"%p",&p);
// 对象地址
NSLog(@"%p",p);
// <类名:对象地址>
NSLog(@"%@",p);
SEL:
1.方法存储的位置