OC基础-关于构造方法

一 init的疑惑

init是OC的构造方法,也即是初始化方法。init常见于创建对象实例,假如现有Person这个类,新建一个Person对象实例时:

Person *person = [ [Person alloc] init];

以上代码执行的时候,实际实现了以下三个过程:

  • 向Person类发送了alloc消息,在堆内存中创建了该类的对象
  • 对象收到init消息后,进行对象的初始化
  • 返回对象中堆内存中的地址,赋值给person指针变量

1 未重写init方法

给对象分配内存空间后,需要初始化对象,才能使用该对象。但后来自己做了尝试,当给对象分配内存后,不初始化对象,还是可以操作对象中的实例变量和方法的:

// Person.h
#import <Foundation/Foundation.h>
@interface Person : NSObject
@property NSString *name;
@property int age;
/** 测试方法*/
- (void)testMethod;
@end
// Person.m
#import "Person.h"
@implementation Person
- (void)testMethod {
    NSLog(@"This is test method.");
}
@end

然后在main.m中创建对象来进行测试:

// main.m
#import <Foundation/Foundation.h>
#import "Person.h"
int main(int argc, const char * argv[]) {
    @autoreleasepool {   
        // 为Person对象申请内存空间,但未初始化 
        Person *person = [Person alloc];
        NSLog(@"\nperson: %@\nName: %@\nAge: %d",
              person, person.name, person.age);
        [person testMethod];
    }
    return 0;
}

输出结果:

2015-08-08 23:50:23.223 OC-类的练习01[484:9197] 
person: <Person: 0x100206730>
Name: (null)
Age: 0
2015-08-08 23:50:23.224 OC-类的练习01[484:9197] This is test method.

2 重写init方法

在以上代码的基础上,重写Person类的init方法:

// Person.m
#import Person.h
@implementation Person
- (void)testMethod {
    NSLog(@"This is test method.");
}

- (instancetype)init {
    if (self = [super init]) {
        _age = 1;
        _name = @"Test";
    }
    return self
}
@end

再在main.m中添加测试代码:

// main.m
#import <Foundation/Foundation.h>
#import "Person.h"
int main(int argc, const char * argv[]) {
    @autoreleasepool {   
        // 为Person对象申请内存空间,但不初始化 
        Person *person = [Person alloc];
        NSLog(@"\nperson: %@\nName: %@\nAge: %d",
              person, person.name, person.age);
        [person testMethod];
        // 初始化对象
        person = [person init];
        NSLog(@"\nperson: %@\nName: %@\nAge: %d",
              person, person.name, person.age);
    }
    return 0;
}

输出结果:

2015-08-09 09:55:19.059 OC-类的练习01[458:9440] 
person: <Person: 0x1001064f0>
Name: (null)
Age: 0
2015-08-09 09:55:19.060 OC-类的练习01[458:9440] This is test method.
2015-08-09 09:55:19.060 OC-类的练习01[458:9440] 
person: <Person: 0x1001064f0>
Name: Test
Age: 1

个人理解是,在向Person类发送alloc消息创建了对象后,内存已经将实例变量设为了最原始的值,比如这里的Age默认0,Name默认null,并可以操作其对象方法。而在未重写init方法之前发送init消息时,Age和Name的值保持跟未初始化时一致。在重写了init方法之后,再发送init消息时,则按照重写方法来设置属性的初始值。

不过很迷惑,这跟书上的说法不一致。《ios编程》原话:任何一个对象都必须在创建并且初始化后才能使用(page31)。在网上未能找到更详尽的解释,后续如有新的进展再做跟进。

二 定制自己的初始化方法

默认的init方法不一定适用每个场景,有时需要定制自己的初始化方法。继续以Person类作扩展,在Person.h中声明initWithName:(NSString *)name Age:(int)age方法:

// Person.h
@interface Person : NSObject
    ...
/** 定制自己的初始化方法*/
- (instancetype)initWithName:(NSString *)name Age:(int)age;
@end

并在Person.m中添加以下代码:

// Person.m
#import Person.h
@implementation Person
    ...
- (instancetype)initWithName:(NSString *)name Age:(int)age {
    if (self = [super init]) {
        _name = name;
        _age = age;
    }
    return self;
}
@end

在main.m中删除之前的测试代码,直接采用自定义的初始化方法来创建对象:

// main.m
#import <Foundation/Foundation.h>
#import "Person.h"

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        // 采用自定义初始化方法创建对象 
        Person *person = [[Person alloc] initWithName:@"Tom Smith" Age:20];
        NSLog(@"\nName: %@\nAge: %d", person.name, person.age);    
    }
    return 0;
}

输出结果:

2015-08-09 10:20:50.780 OC-类的练习01[471:13356] 
Name: Tom Smith
Age: 20

三 重写description方法

description方法,其实类似于java中的toString方法。如果以“NSLog(@"%@", person);”的形式打印时,只会输出person对象的内存地址,重写该方法可以输出我们需要的信息:

// Person.m
@implementation Person
    ...
- (NSString *)description {
    return [[NSString alloc] initWithFormat:@"\nDescription\nName: %@\nAge: %d",
        _name, _age];
}
@end

然后在main.m中直接打印:

// main.m
#import <Foundation/Foundation.h>
#import "Person.h"

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        // 采用自定义初始化方法创建对象 
        Person *person = [[Person alloc] initWithName:@"Tom Smith" Age:20];
        NSLog(@"%@", person);    
    }
    return 0;
}

输出结果:

2015-08-09 10:41:50.242 OC-类的练习01[494:17251] 
Description
Name: Tom Smith
Age: 20
时间: 2024-08-25 12:03:08

OC基础-关于构造方法的相关文章

黑马程序员---OC基础5【点语法】【@property关键字】【@synthesize关键字】【id类型】【动态类型】【构造方法】

------Java培训.Android培训.iOS培训..Net培训.期待与您交流! ------- [点语法] 1 1.使用“点语法” 2 Student *stu= [[Student alloc]init]; 3         //调用set方法 4         [stu setAge:20]; 5         [stu setName:@"Jone"]; 6         //点语法:xcode的特性,Xcode帮我们做了代码替换 7         //点语法,

OC基础 04

OC 基础04 [email protected]基本概念 >[email protected]是编译器的指令 >[email protected] 用在声明文件中告诉编译器声明成员变量的的访问器(getter/setter)方法 这样的好处是:免去我们手工书写getter和setter方法繁琐的代码 @property基本使用 1.在@inteface中,用来自动生成setter和getter的声明 示例: 用@property int age; // 就可以代替下面的两行 - (int)a

黑马程序员--oc基础第十篇(foundation框架下、集合)

十 . oc基础(Foundation框架下) 1.下面介绍几种OC对象类型的存储结构:NSArray,NSDictionary,NSSet,以及基本数据类型封装类. NSNumber:*既然这几种数据结构都是用来存放对象类型的那么基本数据类型想要放入其中就要先对他们进行封装.使用NSNumber对基本数据类型进行封装. // // Created by keeganlee on 15/3/2. // Copyright (c) 2015年 keeganlee. All rights reser

OC基础01

搜索 "==>" 寻找标记 OC基础总结: Objective-C具有相当多的动态特征,如: " 动态类型 , 动态绑定 , 动态加载" ==> copy mutableCopy 浅复制: 在复制操作中,对于被复制的对象的每一层复制都是指针复制. 深复制: 在复制操作中,对于被复制的对象至少有一层是对象复制 完全复制: 在复制操作中,对于被复制的对象的每一层都是对象复制. 一般来讲: 浅复制复制引用对象的指针 深复制 复制引用对象的内容 retain &

【OC基础语法考试】

OC基础语法已经全部学完,但是这些知识只是最基础的,还有很多高级知识,这个可能需要后面慢慢的去学习才能体会到.接下来我会总结前面的OC基础语法,如果大家发现有什么不正确的地方,请指正,小弟是新生,多请OC老鸟来喷~~ 试题如下: 1.将包含以下三个字符串@“1hello“,@“2word“,@”3good“的数组改写为字典,数字部分作为key,英文部分作为value.(15) 2.建立一个数组对象,使用3个不同的方法,使其引用计数增加为4,输出这个值,然后保证内存能够正确释放.(15) 3.使用

四.OC基础--1.文档安装和方法重载,2.self和super&amp;static,3.继承和派生,4.实例变量修饰符 ,5.私有变量&amp;私有方法,6.description方法

四.OC基础--1.文档安装和方法重载, 1. 在线安装 xcode-> 系统偏好设置->DownLoads->Doucument->下载 2. 离线安装 百度xcode文档 3. 方法重载: 是指在一个类中定义多个同名的方法 在OC中没有重载 2.self和super&static, self和super: 1. self理解: 谁调用当前方法, self就代表谁. 比如: 在对象方法中,self代表的是对象, 因为只有对象才可以调用对象方法 在类方法中, self代表的

OC基础 可变字典与不可变字典的使用

OC基础 可变字典与不可变字典的使用 1.不可变字典 1.1创建不可变字典 //创建字典 //注意: //1,元素个数是偶数 //2,每两个元素是一个键值对 //3,值在前,键在后 NSDictionary *dic = [[NSDictionary alloc] initWithObjectsAndKeys:@"huang",@"name",@"30",@"age", nil]; NSLog(@"%@",

OC基础(23)

NSArray基本概念 NSArray 遍历 NSArray排序 NSArray文件读写 NSArray 与字符串 *:first-child { margin-top: 0 !important; } body > *:last-child { margin-bottom: 0 !important; } a { color: #4183C4; } a.absent { color: #cc0000; } a.anchor { display: block; padding-left: 30p

黑马程序员--oc基础第六篇

六. oc基础知识(内存管理下) 总结:内存管理代码规范 1.只要调用alloc那么就必须调用release: 2.set方法的代码部分 *基本数据类型直接赋值. *如果是oc对象类型 - (void) setCar:(Car *)car { if(_car!=car) { [_car release]; _car=[Car retain]; } } 3.dealloc 部分的代码规范 *一定要[super dealloc ]放在最后面. *对self(当前)所拥有的其他对象做一次release

附录A培训实习生-面向对象基础(2):构造方法和带参数的构造方法

构造方法,又叫构造函数,其实就是对类进行实例化.构造方法与类同名,无返回值,也不需要void,在new时候调用.也就是说,就是调用构造方法的时候. 所有类都有构造方法,如果你不编码则系统默认生成空的的构造方法,如你有定义构造方法,那么默认的构造方法就会失效. 有参数的构造方法:比如我们希望每个小猫一诞生都有姓名,那么就应该写一个有参数的构造方法. 这是一个有参数的构造方法,可以看下: 1 using System; 2 using System.Collections.Generic; 3 us