一
点语法 ,OC 中的点语法还是方法调用
p.age = 10; //这行代码会会自动转成 set方法 [p setAge:10];
下面用法会引发死循环
- (void)setAge:(int)age
{
//_age = age;
NSLog(@"setAge:");
// 会引发死循环
//self.age = age; // [self setAge:age];
}
- (int)age
{
NSLog(@"age");
return _age;
// 会引发死循环
//return self.age;// [self age];
}
二 成员变量作用域
@public : 在任何地方都能直接访问对象的成员变量
@private : 只能在当前类的对象方法中直接访问(@implementation中默认是@private)
@protected : 可以在当前类及其子类的对象方法中直接访问 (@interface中默认就是@protected)
@package : 只要处在同一个框架中,就能直接访问对象的成员变量
@interface和@implementation中不能声明同名的成员变量
@implementation Person
{
int _aaa;// 默认就是私有
int _bbb;
// @implementation中不能定义和@interface中同名的成员变量
三 @property
@property:可以自动生成某个成员变量的setter和getter声明
@property int age;
@property int height;
@synthesize自动生成age的setter和getter实现,并且会访问_age这个成员变量
@synthesize age = _age;
@synthesize height = _height;
@synthesize speed = _speed, wheels = _wheels;
会访问_speed这个成员变量,如果不存在,就会自动生成@private类型的_speed变量
四 id
1 id 是万能指针,能指向任何OC 对象 相当于BSObject*
例如 可以在Person类中创建类对象
id d = [Person new];
五 构造方法
1
构造方法:用来初始化对象的方法,是个对象方法,-开头
重写构造方法的目的:为了让对象创建出来,成员变量就会有一些的值
2重写构造方法的注意点
1.先调用父类的构造方法([super init])
2.再进行子类内部成员变量的初始化
1.调用+alloc分配存储空间
Person *p1 = [Person alloc];
2.调用-init进行初始化
Person *p2 = [p1 init];
调用-init进行初始化
Person *p3 = [Person new]
初始化成员变量的值并赋值
重写-init方法
3 - (id)init
{
// 1.一定要调用回super的init方法:初始化父类中声明的一些成员变量和其他属性
self = [super init]; 当前对象 self
// 2.如果对象初始化成功,才有必要进行接下来的初始化
if (self != nil)
{ 初始化成功/ _age = 10;
}
初始化完成后age 属性就是10
3.返回一个已经初始化完毕的对象
return self;
}
4 自定义构造方法
自定义构造方法的规范
1.一定是对象方法,一定以 - 开头
2.返回值一般是id类型
3.方法名一般以initWith开头
例如 - (id)initWithName:(NSString *)name; 方法声明写在@interface里面
下面是方法实现 在@implementation里面
- (id)initWithName:(NSString *)name
{
if ( self = [super init] )
{
_name = name;
}
return self;
}
精髓思想,子类方式实现时 想拥有父类的属性,直接调用父类的方法,
父类的属性交给父类方法去处理,子类方法处理子类自己的属性
- (id)initWithName:(NSString *)name andAge:(int)age andNo:(int)no
{
将name、age传递到父类方法中进行初始化
if ( self = [super initWithName:name andAge:age])
{
_no = no;
}
return self;
}
六 分类
分类的作用:在不改变原来类内容的基础上,可以为类增加一些方法
使用注意:
1.分类只能增加方法,不能增加成员变量
2.分类方法实现中可以访问原来类中声明的成员变量
3.分类可以重新实现原来类中的方法,但是会覆盖掉原来的方法,会导致原来的方法没法再使用
4.方法调用的优先级:分类(最后参与编译的分类优先) --> 原来类 --> 父类
优先去分类中查找,然后再去原来类中找,最后再去父类中找
七 类的本质
1.当程序启动时,就会加载项目中所有的类和分类,而且加载后会调用每个类和分类的+load方法。只会调用一次。
2.当第一次使用某个类时,就会调用当前类的+initialize方法
3.先加载父类,再加载子类(先调用父类的+load方法,再调用子类的+load方法)
先初始化父类,再初始化子类(先调用父类的+initialize方法,再调用子类的+initialize方法)
类本身也是一个对象,是个Class类型的对象,简称类对象
利用Class 创建 Person类对象
利用 Person类对象 创建 Person类型的对象
当程序启动的时候,就会加载一次项目中所有的类。类加载完毕后就会调用+load方法
+ (void)load
{
NSLog(@"Person---load");
}
当第一次使用这个类的时候,就会调用一次+initialize方法
+ (void)initialize
{
NSLog(@"Person-initialize");
}
八 description方法
Class c = [Person class];
1.会调用类的+description方法
2.拿到+description方法的返回值(NSString *)显示到屏幕上
NSLog(@"%@", c)
默认情况下,利用NSLog和%@输出对象时,结果是:<类名:内存地址>
1.会调用对象p的-description方法
2.拿到-description方法的返回值(NSString *)显示到屏幕上
3.-description方法默认返回的是“类名+内存地址”
决定了实例对象的输出结果
- (NSString *)description
{
下面代码会引发死循环
NSLog(@"%@", self);
九 SEL
SEL其实是对方法的一种包装,将方法包装成一个SEL类型的数据,去找对应的方法地址。找到方法地址就可以调用方法
寻找方法的过程:
(1)首先把test这个方法名包装成sel类型的数据;
(2)根据SEL数据找到对应的方法地址;
(3)根据方法地址调用相应的方法。
(4)注意:在这个操作过程中有缓存,第一次找的时候是一个一个的找,非常耗性能,之后再用到的时候就直接使用。
关于_cmd:每个方法的内部都有一个-cmd,代表着当前方法
|
|