---------------------- Java培训、Android培训、iOS培训、.Net培训、期待与您交流! ----------------------
===== 类方法 =====
类方法 : 使用类名来调用的方法. 以 + 标记.
使用场合: 使用类方法代替对象方法可以提高性能.
类方法比对象方法优化体现在不用创建对象就能执行行为. 在内存中, +识别为类方法, 直接去类的存储空间中调用方法. 对象方法则需要通过对象指针访问对象, 通过isa指针访问类空间, 才能调用到方法.
定义一个类方法 : 声明 + 实现
@interface Person : NSObject
// 声明一个类方法
+ (void) printClassName;
@end
@implementation Person
// 类方法的实现
+ (void) printClassName {
NSLog(@"Class: Person");
}
@end
int main() {
// 使用类名来调用类方法
[Person printClassName];
return 0;
}
+开头的方法 和 -开头的方法是不同的. 类不能调用对象的方法, 对象不能调用类的方法. 否则(编译链接可以通过)运行时会报错 -找不到相应的类/对象方法.
因为类方法和对象方法不同, 所以可以有同名的类方法和对象方法.
+ (void) test;
- (void) test;
上面两个方法是可以同时存在的. 但是不能有两个同名的对象方法.
注意: 成员变量也叫实例变量, 是只有实例(对象)才有的变量, 类没有成员变量. 在内存中, 对象里有存储空间存放成员变量的值,类的空间里是没有存放成员变量的地方的, 所以类没有成员变量的值, 类方法不能访问成员变量.
所以, 如果方法中需要访问成员变量, 就要写成对象方法. 如果不需要访问成员变量, 就可以写成类方法.
类方法的好处: 不依赖于对象, 执行效率高. 能用类方法(不需要成员变量)尽量用类方法.
使用: 当方法内部不需要访问成员变量时, 就可以使用类方法.
===== self 关键字的使用 =====
self 是个指针, 指向调用它的变量 (可能是类, 也可能是对象).谁调用它,它就指向谁。
self关键字不以@开头.
1>使用self调用成员变量:
@interface Person : NSObject
{
int _age;
}
- (void) setAge:(int)age;
- (int) age;
- (void) printAge;
@end
在对象的方法里可以使用self关键字, self就指向调用这个方法的对象.
- (void) setAge:(int)age {
self->_age = age;//和 _age = age; 是等价的
}
2>使用self调用对象方法或者类方法:
- (void) bark {
NSLog(@"Woof!");
}
- (void) barkAndYell {
[self bark]; // 使用self调用其它对象方法
NSLog(@"Wooooooool");
}
注意:1> 注意如果在方法内部调用这个方法本身, 会造成递归, 可能会导致无限循环.
2> 注意对象方法中的self代表对象, 如果调用其它方法调用的是对象方法. 类方法中的self代表调用的类, 在类方法中使用self调用的是类方 法. (Java中的this只能代表对象, 不能代表类). 对象方法中的self不能去调用类方法, 类方法中的self不能去调用对象方法.
3> self不能去调用函数, 函数只能通过函数名(参数)方式调用, 不可以通过self调用.
===== 构造方法 =====
构造方法就是初始化对象的方法.
系统默认的方法为 new 方法,+new是一个类方法, 用来创建一个对象, 但是new方法把所有属性的值初始化为0, 在开发中不常用.
new方法包括 +alloc 方法 与 -init方法,其中 +alloc 方法分配空间,-init方法初始化对象(系统默认值为0)。
=== 重写init方法 ===
init就是构造方法, 用来初始化对象. 构造方法是对象方法, 因为它需要设置成员变量的值.
默认构造方法中所有的成员变量的值都设为0. 我们想让新建对象时成员变量的默认值不是0, 可以自己重写构造方法.
-init 的方法是父类NSObject的方法. 可以在子类中重写.
在类的实现中重写 (重写方法可以不用声明, 直接实现就可以)
@implementation Person
- (id) init {
// 必须要先调用父类的init方法进行初始化, 因为父类中声明的成员变量子类也有, 需要在init中初始化(比如把isa指针指向类).
self = [super init]; // 初始化父类的成员变量, 返回初始化好的对象
// 判断是否初始化成功
if (self != nil) {
// 给当前类的成员变量赋值
_age = 20;
}
// 返回已经初始化完毕的对象
return self;
}
@end
也可以简写成如下形式:
- (id) init {
if (self = [super init]) { // 调用父类方法初始化, 并判断self是否有值
_age = 20; // 给成员变量赋值
}
return self; // 返回初始化完毕的对象
}
这样写后,声明的Person类的年龄都是20。
重写init方法时, 对象的成员变量初始值只能是固定的值. 自定义构造方法可以在初始化时给成员变量赋不同的初值.
# 自定义构造方法
自定义的构造方法需要声明和实现 (重写父类的方法不需要声明)
自定义构造方法的规范 :
1> 是对象方法
2> 返回值是id类型
3> 方法名以init开头 (方便程序员之间的交流, 一看就知道是构造方法)
4> 方法内部的格式和重写init的格式相同 : 调用super的方法并判断空值, 给自己的成员变量赋值, 返回对象
5> 注意, 如果有继承, 通常只给自己的成员变量直接赋值, 父类的成员变量通过调用父类的初始化方法对其赋值
@interface Person : NSObject
@property NSString *name;
@property int age;
// 添加自定义构造方法
- (id) initWithName:(NSString *)name;
- (id) initWithName:(NSString *)name andAge:(int)age;
@end
@implementation Person
// 重写init方法, 默认名字为John
- (id) init {
if (self = [super init]) {
_name = @"John";
}
return self;
}
// 实现自定义的构造方法
- (id) initWithName:(NSString *)name {
if (self = [super init]) { // 和重写init方法是同样的步骤
_name = name;
}
return self;
}
- (id) initWithName:(NSString *)name andAge:(int)age {
if (self = [super init]) {
_name = name;
_age = age;
}
return self;
}
@end
int main() {
Person *p = [[Person alloc] initWithName:@"Rose" andAge:18]; // 调用自己写的初始化方法新建对象
return 0;
}
# 子类对象的初始化 #
比如, Student类是Person的子类, 比Person类多了一个属性_no, 我们想给Student添加初始化方法
@interface Student : Person
@property int no;
- (id) initWithNo:(int)no;
- (id) initWithName:(NSString *)name andAge:(int)age andNo:(int)no;
@end
@implementation Student
- (id) initWithNo:(int)no {
if (self = [super init]) {
_no = no;
}
return self;
}
- (id) initWithName:(NSString *)name andAge:(int)age andNo:(int)no {
if (self = [super init]) {
_no = no;
// _name = name; 错误. 因为_name在父类中是@private, 不可以通过_name访问
// [self setName:name]; 可以使用set方法设置, 但是不建议
// self.age = age; 也可以使用点语法, 但是也不建议这样做
// 如何合理的初始化父类提供的属性, 最好使用父类的初始化方法, 见下面
}
return self;
}
@end
int main() {
Student *s = [[Student alloc] initWithNo:2];
return 0;
}
新建Student对象并把学号赋值为2, 会发现s的_name属性的值为"John", 因为在Person的init方法中将_name默认值赋值为"John".
如果要给Student对象赋父类的成员变量值, 不能直接使用父类的成员变量名(私有), 要调用父类的set方法给成员变量赋值. 但是不建议这么做. 最好使用父类的初始化方法来初始化它提供的属性值:
- (id) initWithName:(NSString *)name andAge:(int)age andNo:(int)no {
if (self = [super initWithName:name andAge:age]) { // 调用父类的初始化方法
_no = no;
}
return self;
}
这样写最好. 父类的成员变量就使用父类的方法来给它初始化. 自己的成员变量自己初始化.
这样的话, 如果父类的init方法对成员变量的初始值有特别的设置或者筛选, 那么子类的初始化方法里就不需要再写一遍, 直接使用父类的初始化方法安全又方便.
本文详细探讨了Objective-C与Swift作为iOS开发语言的优势与区别,介绍了如何在实际项目中灵活运用这两种语言,提升开发效率与代码质量。

被折叠的 条评论
为什么被折叠?



