OC基础(11)

自定义构造方法

本小节知识:

  1. 【掌握】自定义构造方法

1.自定义构造方法

  • 有时候仅仅靠重写构造方法(初始化方法),不能满足需求。比如一个班级中不可能所有学生的年龄都一样,这时候我们需要在创建某个学生的时候能够传入这个学生的年龄。这时候就需要来自定义构造函数(初始化函数)

  • 自定义构造方法的规范

    • (1)一定是对象方法,以减号开头
    • (2)返回值一般是instancetype类型
    • (3)方法名必须以initWith开头
  • 示例

@interface Person : NSObject

@property int age;

@property NSString *name;

// 当想让对象一创建就拥有一些指定的值,就可以使用自定义构造方法
- (id)initWithAge:(int)age;

- (id)initWithName:(NSString *)name;

- (id)initWithAge:(int)age andName:(NSString *)name;

@end

自定义类工厂方法

本小节知识:

  1. 【掌握】自定义类工厂方法
  2. 【掌握】子父类中的类工厂方法

1.自定义工厂方法

  • 什么是工厂方法(快速创建方法)

    • 类工厂方法是一种用于分配、初始化实例并返回一个它自己的实例的类方法。类工厂方法很方便,因为它们允许您只使用一个步骤(而不是两个步骤)就能创建对象. 例如new
  • 自定义类工厂方法的规范

    • (1)一定是+号开头
    • (2)返回值一般是instancetype类型
    • (3)方法名称以类名开头,首字母小写
  • 示例

+ (id)person;
+ (id)person
{
    return  [[Person alloc]init];
}

+ (id)personWithAge:(int)age;
+ (id)personWithAge:(int)age
{
    Person *p = [[self alloc] init];
    [p setAge:age];
    return p;
}
  • apple中的类工厂方法
其实苹果在书写工厂方法时也是按照这样的规划书写
    [NSArray array];
    [NSArray arrayWithArray:<#(NSArray *)#>];
    [NSDictionary dictionary];
    [NSDictionary dictionaryWithObject:<#(id)#> forKey:<#(id<NSCopying>)#>];
    [NSSet set];
    [NSSet setWithObject:<#(id)#>];

2.子父类中的类工厂方法

  • 由于之类默认会继承父类所有的方法和属性, 所以类工厂方法也会被继承
  • 由于父类的类工厂方法创建实例对象时是使用父类的类创建的, 所以如果子类调用父类的类工厂方法创建实例对象,创建出来的还是父类的实例对象
  • 为了解决这个问题, 以后在自定义类工厂时候不要利用父类创建实例对象, 改为使用self创建, 因为self谁调用当前方法self就是谁

  • 示例

@interface Person : NSObject
+ (id)person;
@end

@implementation Person
+ (id)person
{
    return  [[Person alloc]init];
}
@end

@interface Student : Person
@property NSString *name;
@end

@implementation Student

@end

int main(int argc, const char * argv[])
{
    Student *stu = [Student person];// [[Person alloc] init]
    [stu setName:@"lnj"]; // 报错, 因为Person中没有setName
}
  • 正确写法
@interface Person : NSObject
+ (id)person;
@end

@implementation Person
+ (id)person
{
//   return  [[Person alloc]init];
//     谁调用这个方法,self就代表谁
//    注意:以后写类方法创建初始化对象,写self不要直接写类名
    return  [[self alloc]init];
}
@end

@interface Student : Person
@property NSString *name;
@end

@implementation Student
@end

int main(int argc, const char * argv[])
{
    Student *stu = [Student person];// [[Student alloc] init]
    [stu setName:@"lnj"];
}

构造方法

本小节知识:

  1. 【掌握】重写init方法
  2. 【理解】练习
  3. 【掌握】构造方法使用注意
  4. 【掌握】instancetype的作用

1.重写init方法

  • 想在对象创建完毕后,成员变量马上就有一些默认的值就可以重写init方法

  • 重写init方法格式:

- (id)init {
    self = [super init];
    if (self) {
        // Initialize self.
    }
    return self;
}
+ [super init]的作用:

面向对象的体现,先利用父类的init方法为子类实例的父类部分属性初始化。 + self 为什么要赋值为[super init]: 简单来说是为了防止父类的初始化方法release掉了self指向的空间并重新alloc了一块空间。还有[super init]可能alloc失败,这时就不再执行if中的语句。

  • 重写init方法其它格式
- (id)init {
    if (self = [super init]) {
        // Initialize self.
    }
    return self;
}

2.练习

  • 要求通过Person类创建出来的人初始化值都是10岁。
@implementation Person

- (instancetype)init
{
    if (self = [super init]) {
        _age = 10;
    }
    return self;
}
@end
  • 让学生继承人类,要求学生对象初始化之后,年龄是10,学号是1,怎么办?
@implementation Person

- (instancetype)init
{
    if (self = [super init]) {
        _age = 10;
    }
    return self;
}
@end

@implementation Student

- (instancetype)init
{
    if (self = [super init]) {
        _no = 1;
    }
    return self;
}
@end

3.构造方法使用注意

  • 子类拥有的成员变量包括自己的成员变量以及从父类继承而来的成员变量,在重写构造方法的时候应该首先对从父类继承而来的成员变量先进行初始化。
    • 原则:先初始化父类的,再初始化子类的。
      • 先调用父类的构造方法[super init];
      • 再进行子类内部成员变量的初始化。
  • 千万不要把self = [super init]写成self == [super init]

  • 重写构造方法的目的:为了让对象方法一创建出来,成员变量就会有一些固定的值。

4.instancetype的作用

  • instancetype与id相似,不过instancetype只能作为方法返回值,它会进行类型检查,如果创建出来的对象,赋值了不相干的对象就会有一个警告信息,防止出错。
// init此时返回值是id
NSString *str = [[Person alloc] init];
// Person并没有length方法, 但是id是动态类型, 所以编译时不会报错
NSLog(@"length = %i", str.length);
// init此时返回值是instancetype
// 由于instancetype它会进行类型检查, 所以会报警告
NSString *str = [[Person alloc] init];
NSLog(@"length = %i", str.length);
instancetype *p = [[person alloc] init];
// 错误写法instancetype只能作为返回值

继承中的自定义构造方法

本小节知识:

  1. 【掌握】继承中的自定义构造方法

2. 【掌握】自定义构造方法的使用注意

1.继承中的自定义构造方法

  • 不能在子类访问父类私有变量
@interface Person : NSObject

@property int age;

- (id)initWithAge:(int)age;
@end



@interface Student : Person

@property NSString *name;

- (id)initWithAge:(int)age andName:(NSString *)name;
@end

@implementation Student

- (id)initWithAge:(int)age andName:(NSString *)name
{
    if (self = [super init]) {
//        这个_Age是父类中通过property自动在.m中生成的无法继承,不能直接访问
//        _age = age;
        [self setAge:age];
        _name = name;
    }
    return self;
}
@end
  • 父类的属性交给父类的方法来处理
@interface Person : NSObject

@property int age;

- (id)initWithAge:(int)age;
@end



@interface Student : Person

@property NSString *name;

- (id)initWithAge:(int)age andName:(NSString *)name;
@end

@implementation Student

- (id)initWithAge:(int)age andName:(NSString *)name
{
    if (self = [super initWithAge:age]) {
        _name = name;
    }
    return self;
}
@end

2.自定义构造方法的使用注意

  • (1)自己做自己的事情
  • (2)父类的属性交给父类的方法来处理,子类的方法处理子类自己独有的属性

  • 自定义构造方法必须以intiWith开头,并且’W’必须大写


原文地址:https://www.cnblogs.com/zhoudaquan/p/5015790.html