• 黑马程序员-OC的构造方法init以及自定义构造方法


    • 之前我们利用类来创建对象用到了一个类方法new,可是new方法具体是怎么执行的呢?例如
    1 Person *p = [Person new];

    程序只要执行了这一行代码,内存中就会有一个Person类和Person对象,并且Person对象的所有实例变量都初始化为0,并且还有个isa指针指向Person类,那么这个对象实际上是通过两部产生的:第一步,调用Person类的alloc类方法分配一定的内存空间给Person对象,它的返回值就是对象本身,实际上也是这一段内存空间的首地址;第二步,调用对象init方法初始化对象的所有实例变量,并返回对象本身。由于OC本身的init方法很死板,他就是将所有实例变量初始化为0,但是用户往往是希望创建完了一个对象后,希望对象的某些实例变量有一个非0的初始值,所以重写init方法是很重要的。init方法的一般固定格式为

     1 - (id)init{
     2     // 调用父类的init方法将返回值赋值给当前对象
     3     self = [super init]; // 固定写法
     4     
     5     if( self != nil ){
     6         //需要自定义初始化的成员变量
     7     }
     8     // 对象初始化为我们想要的结果后,将对象本身返回
     9     return self;
    10 }

    当然上述代码也可以简化为:

    1 - (id)init{
    2     
    3     if( self = [super init] ){
    4         //需要自定义初始化的成员变量
    5     }
    6     // 对象初始化为我们想要的结果后,将对象本身返回
    7     return self;
    8 }

    代码实现:

     1 #import <Foundation/Foundation.h>
     2 /*******Person类******/
     3 @interface Person : NSObject
     4 
     5 @property int age;
     6 
     7 - (id)init;
     8 
     9 @end
    10 
    11 @implementation Person
    12 
    13 - (id)init{
    14     if ( self = [super init] ) {
    15         _age = 1;
    16     }
    17     
    18     return self;
    19 }
    20 
    21 @end
    22 
    23 /*******Student类*******/
    24 @interface Student : Person
    25 
    26 @property int score;
    27 
    28 - (id)init;
    29 
    30 @end
    31 
    32 @implementation Student
    33 
    34 - (id)init{
    35     if ( self = [super init] ) {
    36         _score = 60;
    37     }
    38     
    39     return self;
    40 }
    41 
    42 @end
    43 
    44 int main() {
    45     // 创建对象并调用调用重写的init对象方法
    46     Person *p = [[Person alloc] init];
    47     Student *stu = [[Student alloc] init];
    48     
    49     // 测试init方法是否成功调用
    50     NSLog(@"Person对象:年龄的初始值为%d", p.age);
    51     NSLog(@"Student对象:年龄的初始值为%d,成绩的初始值为%d", p.age, stu.score);
    52     return 0;
    53 }
    • 但是这种重写init方法也有弊端,因为所有通过重写的init方法创建出来的对象的初始值都是一样的,即使他们都不为0,比如每个学生的姓名是不一样的,自然我们会想到自己写一个初始化方法来满足用户的要求,那么这种自定义的构造方法有什么规范呢?首先,方法名必须以init开头;其次因为是对象方法,所以是以减号'-'开头,并且它的返回值是oc对象,所以返回值为id类型;最后在方法里一定要调用父类对象方法[super init]

    假如有一个Person类,它有实例变量_age(int型)和_name(NSString *型),如果我要想每创建一个Person对象出来后它的_age和_name都不一样,我们可以采取自定义构造方法

     1 /*
     2 定义一个Person类,实例变量_age(int类型)和_name(NSString类型)
     3  要求:自定义一个构造方法,对象被创建出来后,_name和_age都有一个非0值
     4  
     5  */
     6 #import <Foundation/Foundation.h>
     7 
     8 @interface Person : NSObject
     9 
    10 @property int age;
    11 @property NSString *name;
    12 
    13 - (id)initWithName:(NSString *)name andAge:(int)age;
    14 
    15 @end
    16 
    17 @implementation Person
    18 
    19 - (id)initWithName:(NSString *)name andAge:(int)age{
    20     if ( self = [super init] ) {
    21         _name = name;
    22         _age = age;
    23     }
    24     
    25     return self;
    26 }
    27 
    28 @end
    29 
    30 int main() {
    31     // 创建两个对象并调用调用自定义构造对象方法
    32     Person *p1 = [[Person alloc] initWithName:@"ZhangSan" andAge:15];
    33     
    34     Person *p2= [[Person alloc] initWithName:@"LiSi" andAge:14];
    35     
    36     // 测试自定义构造方法
    37     NSLog(@"第1个Person对象:姓名为%@,年龄为%d", p1.name, p1.age);
    38     NSLog(@"第2个Person对象:姓名为%@,年龄为%d", p2.name, p2.age);
    39     return 0;
    40 }

    程序正常运行

    如果我们要求在这个基础上再添加一个Person类的子类Student并且新添加一个实例变量_no(int类型),并且每创建一个Student类对象_no都有一个自己的初始值。代码如下:

     1 #import <Foundation/Foundation.h>
     2 
     3 /**********Person类***********/
     4 @interface Person : NSObject
     5 
     6 @property int age; // 年龄
     7 @property NSString *name; // 姓名
     8 
     9 - (id)initWithName:(NSString *)name andAge:(int)age; // 自定义name和age的构造对象方法
    10 
    11 @end
    12 
    13 // Person类的实现
    14 @implementation Person
    15 // 自定义构造方法实现
    16 - (id)initWithName:(NSString *)name andAge:(int)age{
    17     if ( self = [super init] ) {
    18         _name = name;
    19         _age = age;
    20     }
    21     
    22     return self;
    23 }
    24 
    25 @end
    26 /***********Student类***********/
    27 @interface Student : Person
    28 
    29 @property int no; // 学号
    30 // 学生的自定义构造方法
    31 - (id)initWithName:(NSString *)name andAge:(int)age andNo:(int)no;
    32 
    33 @end
    34 
    35 // Student类的实现
    36 @implementation Student
    37 // 学生的自定义构造方法的实现
    38 - (id)initWithName:(NSString *)name andAge:(int)age andNo:(int)no{
    39     if ( self = [super init]) {
    40         _no = no;
    41         self.name = name;
    42         self.age = age;
    43     }
    44     return self;
    45 }
    46 
    47 @end
    48 
    49 int main() {
    50     // 创建两个对象并调用调用自定义构造对象方法
    51     Student *stu1 = [[Student alloc] initWithName:@"ZhangSan" andAge:14 andNo:8];
    52     
    53     Student *stu2= [[Student alloc] initWithName:@"LiSi" andAge:15 andNo:2];
    54     
    55     // 测试自定义构造方法
    56     NSLog(@"第1个Student对象:姓名为%@,年龄为%d,学号为%d", stu1.name, stu1.age, stu1.no);
    57     NSLog(@"第2个Student对象:姓名为%@,年龄为%d,学号为%d", stu2.name, stu2.age, stu2.no);
    58     return 0;
    59 }

    但是这个代码中的第41、42行是在子类的对象方法中对父类的实例变量修改值,这是不建议的。假如以后我们修改了父类的某一个属性名的话,那么子类的这种语句就会出错。一般是谁的属性那就用谁的方法去修改它,所以我们要把父类的这两个属性调用父类的方法去修改它,如何完成这个要求呢?我们只需要动一动学生的自定义构造方法的实现:

    1 // 修改后的学生的自定义构造方法的实现
    2 - (id)initWithName:(NSString *)name andAge:(int)age andNo:(int)no{
    3     if ( self = [super initWithName:name andAge:no]) {
    4         _no = no;
    5         //self.name = name;
    6         //self.age = age;
    7     }
    8     return self;
    9 }

    这种做法就保证了子类的属性交给子类去操作,父类的属性交给父类去操作,互不干扰

  • 相关阅读:
    6.12白书第五章图论总结——司雨寒
    【司雨寒】最短路专题总结
    十三 十四周总结
    13周总结--苏康
    JuneX_13
    12总结--苏康
    十二周总结
    每周总结(5.30)——何贤拓
    进阶实验4-3.1 家谱处理 (30分)
    进阶实验2-3.1 海盗分赃 (25分)--递推
  • 原文地址:https://www.cnblogs.com/oucding/p/4422929.html
Copyright © 2020-2023  润新知