【Objective-C】07-自定义构造方法和description方法

2024-08-29 23:38

本文主要是介绍【Objective-C】07-自定义构造方法和description方法,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

知识回顾

在第5讲中已经介绍了如何定义类和创建并初始化对象,比如有Student这个类

1.Student.h

复制代码
1 #import <Foundation/Foundation.h>
2 
3 @interface Student : NSObject {
4     int _age;
5 }
6 - (void)setAge:(int)age;
7 - (int)age;
8 @end
复制代码

 

2.Student.m

复制代码
 1 #import "Student.h"
 2 
 3 @implementation Student
 4 - (void)setAge:(int)age {
 5     _age = age;
 6 }
 7 - (int)age {
 8     return _age;
 9 }
10 @end
复制代码

 

3.在main函数中创建一个Student对象

复制代码
 1 #import "Student.h"
 2 
 3 int main(int argc, const char * argv[])
 4 {
 5 
 6     @autoreleasepool {
 7         Student *stu = [[Student alloc] init];
 8         
 9         stu.age = 10;
10         
11         [stu release];
12     }
13     return 0;
14 }
复制代码

* 在第7行调用Student的alloc方法分配内存,然后再调用init方法初始化对象

* 像init这样用来初始化对象的方法,我们可以称为"构造方法"

 

回到顶部

一、自定义构造方法

默认的构造方法,也就是init方法,它是不接收任何参数的。因此,在实际开发中,为了方便,会经常自定义构造方法。

接下来,自定义一个构造方法,可以传入一个age参数来初始化Student对象

1.在Student.h中添加方法声明

- (id)initWithAge:(int)age;

* 构造方法的方法名一般都会以init开头,返回值跟init方法一样为id类型,id可以代表任何OC对象

* 这个构造方法接收一个int类型的age参数,目的是在初始化Student对象时,顺便设置成员变量_age的值

 

2.在Student.m中实现构造方法

复制代码
1 - (id)initWithAge:(int)age {
2     self = [super init];
3     if (self != nil) {
4         _age = age;
5     }
6     return self;
7 }
复制代码

* 跟Java一样,构造方法内部首先要调用父类的构造方法,在第2行调用了父类的init方法,它会返回初始化好的Student对象,这里把返回值赋值给了self,self代表Student对象本身

* 第3~5行的意思是:如果self不为nil,也就是初始化成功,就给成员变量_age进行赋值

* 最后返回初始化过后的self,整个构造方法就结束了

 

3.简化构造方法

由于C语言和OC的语法特性,我们可以对构造方法进行简化,先简化第3行

复制代码
1 - (id)initWithAge:(int)age {
2     self = [super init];
3     if (self) {
4         _age = age;
5     }
6     return self;
7 }
复制代码

* 第3行的 if(self) 跟 if(self!=nil) 是等价的

* 还可以将第2、3行合并,继续简化

复制代码
1 - (id)initWithAge:(int)age {
2     if ( self = [super init] ) {
3         _age = age;
4     }
5     return self;
6 }
复制代码

* 第2行的总体意思是:先调用父类的构造方法init,然后将返回值赋值给self,接着判断self是否为nil

* 以后的构造方法都这样写了

 

4.调用构造方法

1 Student *stu = [[Student alloc] initWithAge:10];
2 
3 NSLog(@"age is %i", stu.age);
4 
5 [stu release];

* 在第1行调用了构造方法initWithAge:,并传入10作为参数,因此Student对象的成员变量_age会变为10

* 在第3行打印Student的成员变量_age,打印结果:

2013-04-19 21:36:47.880 构造方法[448:303] age is 10

 

回到顶部

二、description方法

1.NSLog回顾

众所周知,我们可以用NSLog函数来输出字符串和一些基本数据类

1 int age = 11;
2 NSLog(@"age is %i", age);

* 第2行的%i代表会输出一个整型数据,右边的变量age会代替%i的位置进行输出

* 输出结果:

2013-04-19 21:43:47.674 构造方法[483:303] age is 11

 

2.NSLog输出OC对象

其实,除了可以输出基本数据类型,NSLog函数还可以输出任何OC对象

1 Student *stu = [[Student alloc] initWithAge:10];
2 
3 NSLog(@"%@", stu);
4 
5 [stu release];

* 在第3行用NSLog函数输出stu对象,注意左边的格式符%@,以后想输出OC对象,就得用%@这个格式符

* NSLog函数一旦发现用%@输出某个OC对象时,就会调用这个对象的description方法(这个方法返回值是NSString类型,是OC中的字符串类型),并且将description方法返回的字符串代替%@的位置进行输出

* description方法的默认实现是返回这样的格式:<类名: 对象的内存地址>,因此上面代码的输出结果为:

2013-04-19 21:46:49.896 构造方法[492:303] <Student: 0x100109910>

Student是类名,0x100109910是对象的内存地址

* 注意了,%@只能用于输出OC对象,不能输出结构体等其他类型

* 有Java开发经验的人应该能感受到OC中的description方法就是Java中的toString方法

 

3.重写description方法

description方法的默认实现是返回类名和对象的内存地址,这样的话,使用NSLog输出OC对象,意义就不是很大,因为我们并不关心对象的内存地址,比较关心的是对象内部的一些成变量的值。因此,会经常重写description方法,覆盖description方法的默认实现

比如,重写Student的description方法,返回成员变量_age的值

1 - (NSString *)description {
2     return [NSString stringWithFormat:@"age=%i", _age];
3 }

* 在第2行调用了NSString这个类的静态方法stringWithFormat初始化一个字符串对象,并返回这个字符串

* 如果你会使用NSLog的话,那就应该能理解第2行的方法参数是什么意思了

* 假如_age是10,那么description方法返回的字符串就是@"age=10"

* 可能有人会觉得奇怪,之前创建的Student对象是需要释放的,为什么这里创建的字符串对象不用释放?要想彻底明白这个问题,需要先了解OC的内存管理,这里我们暂不做详细讨论,后面会有章节详细讨论内存管理。你可以先记住一个规则:一般情况下,静态方法返回的对象,都不用手动释放。

* 重写完description方法后,再次执行下面的代码

1 Student *stu = [[Student alloc] initWithAge:10];
2 
3 NSLog(@"%@", stu);
4 
5 [stu release];

输出结果为:

2013-04-19 22:09:56.625 构造方法[531:303] age=10

 

4.description方法的陷阱

千万不要在description方法中同时使用%@和self,下面的写法是错误的:

1 - (NSString *)description {
2     return [NSString stringWithFormat:@"%@", self];
3 }

第2行同时使用了%@和self,代表要调用self的description方法,因此最终会导致程序陷入死循环,循环调用description方法

这篇关于【Objective-C】07-自定义构造方法和description方法的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1119174

相关文章

Nginx设置连接超时并进行测试的方法步骤

《Nginx设置连接超时并进行测试的方法步骤》在高并发场景下,如果客户端与服务器的连接长时间未响应,会占用大量的系统资源,影响其他正常请求的处理效率,为了解决这个问题,可以通过设置Nginx的连接... 目录设置连接超时目的操作步骤测试连接超时测试方法:总结:设置连接超时目的设置客户端与服务器之间的连接

Java判断多个时间段是否重合的方法小结

《Java判断多个时间段是否重合的方法小结》这篇文章主要为大家详细介绍了Java中判断多个时间段是否重合的方法,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 目录判断多个时间段是否有间隔判断时间段集合是否与某时间段重合判断多个时间段是否有间隔实体类内容public class D

Python使用国内镜像加速pip安装的方法讲解

《Python使用国内镜像加速pip安装的方法讲解》在Python开发中,pip是一个非常重要的工具,用于安装和管理Python的第三方库,然而,在国内使用pip安装依赖时,往往会因为网络问题而导致速... 目录一、pip 工具简介1. 什么是 pip?2. 什么是 -i 参数?二、国内镜像源的选择三、如何

IDEA编译报错“java: 常量字符串过长”的原因及解决方法

《IDEA编译报错“java:常量字符串过长”的原因及解决方法》今天在开发过程中,由于尝试将一个文件的Base64字符串设置为常量,结果导致IDEA编译的时候出现了如下报错java:常量字符串过长,... 目录一、问题描述二、问题原因2.1 理论角度2.2 源码角度三、解决方案解决方案①:StringBui

Linux使用nload监控网络流量的方法

《Linux使用nload监控网络流量的方法》Linux中的nload命令是一个用于实时监控网络流量的工具,它提供了传入和传出流量的可视化表示,帮助用户一目了然地了解网络活动,本文给大家介绍了Linu... 目录简介安装示例用法基础用法指定网络接口限制显示特定流量类型指定刷新率设置流量速率的显示单位监控多个

Java覆盖第三方jar包中的某一个类的实现方法

《Java覆盖第三方jar包中的某一个类的实现方法》在我们日常的开发中,经常需要使用第三方的jar包,有时候我们会发现第三方的jar包中的某一个类有问题,或者我们需要定制化修改其中的逻辑,那么应该如何... 目录一、需求描述二、示例描述三、操作步骤四、验证结果五、实现原理一、需求描述需求描述如下:需要在

JavaScript中的reduce方法执行过程、使用场景及进阶用法

《JavaScript中的reduce方法执行过程、使用场景及进阶用法》:本文主要介绍JavaScript中的reduce方法执行过程、使用场景及进阶用法的相关资料,reduce是JavaScri... 目录1. 什么是reduce2. reduce语法2.1 语法2.2 参数说明3. reduce执行过程

C#中读取XML文件的四种常用方法

《C#中读取XML文件的四种常用方法》Xml是Internet环境中跨平台的,依赖于内容的技术,是当前处理结构化文档信息的有力工具,下面我们就来看看C#中读取XML文件的方法都有哪些吧... 目录XML简介格式C#读取XML文件方法使用XmlDocument使用XmlTextReader/XmlTextWr

C++初始化数组的几种常见方法(简单易懂)

《C++初始化数组的几种常见方法(简单易懂)》本文介绍了C++中数组的初始化方法,包括一维数组和二维数组的初始化,以及用new动态初始化数组,在C++11及以上版本中,还提供了使用std::array... 目录1、初始化一维数组1.1、使用列表初始化(推荐方式)1.2、初始化部分列表1.3、使用std::

oracle DBMS_SQL.PARSE的使用方法和示例

《oracleDBMS_SQL.PARSE的使用方法和示例》DBMS_SQL是Oracle数据库中的一个强大包,用于动态构建和执行SQL语句,DBMS_SQL.PARSE过程解析SQL语句或PL/S... 目录语法示例注意事项DBMS_SQL 是 oracle 数据库中的一个强大包,它允许动态地构建和执行