热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

ObjectiveC对象的初始化(2)——便利初始化函数

0x01便利初始化函数有些对象拥有多个以init开头的方法名,这些方法和普通的方法一样,只是遵循命名规则约定,用init开头表示它用于初

0x01 便利初始化函数

有些对象拥有多个以init开头的方法名,这些方法和普通的方法一样,只是遵循命名规则约定,用init开头表示它用于初始化。

很多类中包含便利初始化函数(Convenience Initializer),它们是用来完成某些额外工作的初始化方法。

 

下面我们用NSString类中的一些初始化方法来举例。

1、基本的初始化方法,返回一个空字符串:

- (id) init;//-----------------------------------------------------------------------NSString *emptyString = [[NSString alloc] init];
//最基本的init对不可变的NSString类来说就仅仅是初始化一个空字符串NSMutableString *emptyMutableString = [[NSString alloc] init];
//但初始化一个NSMutableString类的对象就可以开始向其中添加字符

 

2、带格式化操作的初始化方法,直接返回带格式的字符串,效果类似stringWithFormat:

- (id) initWithFormat: (NSString *) format, ...;//-----------------------------------------------------------------------string = [[NSString alloc] initWithFormat: @"%d or %d", 25, 624];
//This gives you a string with the value of "25 or 624".

这里可以看出Apple建议把alloc和init分开的原因,分配和初始化的功能是不一样的,把初始化步骤独立开来可以为程序带来更多灵活性。

作为Cocoa的编程人员应该熟练地使用alloc+init,而new只是辅助方法。

 

3、使用文件中的内容来初始化字符串:

- (id) initWithContentsOfFile:(NSString *) path encoding:(NSStringEncoding) enc error:(NSError **) error//-----------------------------------------------------------------------NSError *error = nil;
NSStringEncoding encoding = NSUTF8StringEncoding;
NSString *string = [[NSString alloc] initWithContentsOfFile:@"/tmp/words.txt"usedEncoding:&encodingerror:&error];
if(nil != error)
{NSLog(@"Unable to read data from file, %@", [error localizedDescription]);
}

  • @"/tmp/words.txt"指定了文件路径,方法将在该文件读取内容并使用该内容初始化一个字符串;
  • encoding参数将文件内容的类型告诉API,一般来说使用的是NSUTF8StringEncoding;
  • error参数如果初始化正常则返回 nil, 否则返回错误信息。这些错误信息被封装成 NSError 对象,可以使用 NSError 的对象方法: localizedDescription来查明情况,并使用%@格式符打印错误信息;
  • 注意这里的error是指针的指针!

 


0x02 初始化函数的使用

当我们的类对象中存在成员变量时,我们可以用初始化函数对其进行初始赋值。

以Tire类为例,我们将之扩展,用pressure记录胎压,treadDepth记录胎纹深度,所以接口部分修改如下:

#import
@interface Tire : NSObject
{float pressure;float treadDepth;
} //Tire类多了两个成员变量,pressure是胎压,treadDepth是胎纹深度//--------------------pressure的setter/getter方法
-(void) setPressure: (float) pressure;
-(float) pressure;
//--------------------treadDepth的setter/getter方法
-(void) setTreadDepth: (float) treadDepth;
-(float) treadDepth;@end // Tire.h

在Tire类的实现中,为使用者提供了访问tire对象的方法,并提供了初始化函数,最后对description方法也进行了相应的修改:

#import "Tire.h"
@implementation Tire
- (id) init
{if (self = [super init]){pressure = 34.0; treadDepth = 20.0;}return (self);
} // init//初始化完成后,新的tire对象将是带有预置参数值的新对象- (void) setPressure: (float) p
{
pressure = p;
} // setPressure
- (float) pressure
{return (pressure);
} // pressure- (void) setTreadDepth: (float) td
{treadDepth = td;
} // setTreadDepth
- (float) treadDepth
{return (treadDepth);
} // treadDepth- (NSString *) description
{NSString *desc;desc = [NSString stringWithFormat:@"Tire: Pressure: %.1f TreadDepth: %.1f", pressure, treadDepth];return (desc);
} // description@end // Tire.m

因为Tire类关键代码发生了变化,包含了Tire类的Car类也需要进行相应修改,在此就不详述了。

 


0x03 构造便利初始化函数

假设我们要用Tire类创建一个新的tire对象,main()函数节选代码如下:

...
tire = [[Tire alloc] init];
[tire setPressure: 23 + i];
[tire setTreadDepth: 33 - i];
...

为了创建一个新的对象,发送了4个消息,3行代码。

如果Tire类中的成员变量更多,只会让程序显得更加冗长。

为了更快、更方便地执行初始化,我们可以构造一个能同时获得成员变量的便利初始化函数:

@interface Tire : NSObject
{float pressure;float treadDepth;
}
//New Convenience Initializer
- (id) initWithPressure: (float) pressure treadDepth: (float) treadDepth;- (void) setPressure: (float) pressure;
- (float) pressure;
- (void) setTreadDepth: (float) treadDepth;
- (float) treadDepth;@end // Tire

该便利初始化函数的实现非常简单:

- (id) initWithPressure: (float) p treadDepth: (float) td
{if (self = [super init]) {pressure = p;treadDepth = td;
}return (self);
} // initWithPressure:treadDepth:

现在,main()函数中只需一行代码即可完成新tire对象的分配和初始化工作:

...
Tire *tire;
tire = [[Tire alloc] initWithPressure: 23 + i treadDepth: 33 - i];
...

 


0x04 便利初始化函数的缺点

在子类化的时候,为了保证超类能正常初始化,就需要重写超类所有的初始化方法和便利初始化方法,并添加子类成员变量的初始化方法。

但即使我们都重写了这些超类的方法,当超类修改或者添加初始化方法的时候,子类仍然需要做相应的修改。

这样的设计偏离了高内聚低耦合的设计原则!

 


0x05 指定初始化函数

类中的某个初始化方法被指派为指定初始化函数,该类的所有初始化方法都使用指定初始化方法执行初始化操作。

而子类使用其超类的指定初始化方法进行超类的初始化。

通常,接收参数最多的初始化方法是最终的指定初始化函数,通常它最灵活。

因此,对于子类来说,只要重写超类的指定初始化方法就可以解决便利初始化方法的缺点。

为了保证指定初始化函数的顺利执行,所有其他的初始化函数均应该按照initWithPressure:treadDepth:的形式实现:

 

首先修改Tire类:

#import "Tire.h"@implementation Tire- (id) init
{if (self = [self initWithPressure: 34 treadDepth: 20]) {//...}return (self);
} // init- (id) initWithPressure: (float) p
{if (self = [self initWithPressure: p treadDepth: 20.0]) {//...}return (self);
} // initWithPressure- (id) initWithTreadDepth: (float) td
{if (self = [self initWithPressure: 34.0 treadDepth: td]) {//...}return (self);
} // initWithTreadDepth- (id) initWithPressure: (float) p treadDepth: (float) td
{if (self = [super init]) {pressure = p;treadDepth = td;}return (self);
} // initWithPressure:treadDepth:

 

再向Tire类的子类AllWeatherRadial类添加指定初始化函数:

#import "AllWeatherRadial.h"@implementation AllWeatherRadial// 指定初始化函数
- (id) initWithPressure: (float) p treadDepth: (float) td
{self = [super initWithPressure: p treadDepth: td]; //重写超类的指定初始化函数if (self) {rainHandling = 23.7;snowHandling = 42.5;} //添加子类的成员变量值return (self);
} //------------------------------------------------------------------------ (void) setRainHandling: (float) rh
{rainHandling = rh;
} // setRainHandling- (float) rainHandling
{return (rainHandling);
} // rainHandling- (void) setSnowHandling: (float) sh
{snowHandling = sh;
} // setSnowHandling- (float) snowHandling
{return (snowHandling);
} // snowHandling...

 


0x06 子类也可以有指定初始化函数

同理,子类也能给自己指定初始化函数,这样就能让用户在初始化的时候决定自己要的成员变量值:

...//子类也可以有自己的指定初始化函数
- (id)initWithSnowHanding:(float)s andRainHanding:(float)r
{self = [super init];if (self) {self.snowHandling = s;self.rainHandling = r;}return self;
}
...

相应的,在mian()函数中初始化新的tire对象,可以同时调用该initWithSnowHanding:andRainHanding:方法:

#import #import "Car.h"
#import "Slant6.h"
#import "AllWeatherRadial.h"int main(int argc, const char * argv[])
{@autoreleasepool{Car *car = [[Car alloc] init];for (int i = 0; i <4; i++){AllWeatherRadial *tire;//tire = [[AllWeatherRadial alloc] init];//使用子类的指定初始化函数设置成员变量值tire = [[AllWeatherRadial alloc] initWithSnowHanding:11.0 andRainHanding:22.0];[car setTire: tire atIndex: i];}Engine *engine = [[Slant6 alloc] init];[car setEngine: engine];[car print];}return 0;
}//Output:
//AllWeatherRadial: 34.0 / 20.0 / 22.0 / 11.0
//AllWeatherRadial: 34.0 / 20.0 / 22.0 / 11.0
//AllWeatherRadial: 34.0 / 20.0 / 22.0 / 11.0
//AllWeatherRadial: 34.0 / 20.0 / 22.0 / 11.0
//I am a slant-6. VROOOM!
//Program ended with exit code: 0
//

 


0x07 初始化函数规则


  • 如果不需要设置任何状态,或者默认的alloc+init方法效果非常不错,那就不一定要去创建初始化函数;
  • 如果创建了一个指定初始化函数,则一定要在自己的指定初始化函数中调用超类的指定初始化函数;
  • 如果初始化函数不止一个,则需要选择一个作为指定初始化函数;
  • 被选定的方法应该调用超类的的指定初始化函数;
  • 要按照指定初始化函数的形式实现所有其他初始化函数。

 

 


推荐阅读
  • ObjectiveC与Swift之间的互相调用和跳转
    Objective-C与Swift之间的互相调用和跳转-一、OC和Swift互相跳转首先在需要引入Swift的文件中导入头文件#import工程名-Swift.hOC跳转Swift ... [详细]
  • ObjectiveC:语法基础
    OC特点:    1)支持C语法;    2)支持面向对象特性;    3)兼容性好,可以同时在项目中使用OC、C++,也可以引入C、C++库文件;     ... [详细]
  • 开发笔记:加密&json&StringIO模块&BytesIO模块
    篇首语:本文由编程笔记#小编为大家整理,主要介绍了加密&json&StringIO模块&BytesIO模块相关的知识,希望对你有一定的参考价值。一、加密加密 ... [详细]
  • 本文讨论了一个关于cuowu类的问题,作者在使用cuowu类时遇到了错误提示和使用AdjustmentListener的问题。文章提供了16个解决方案,并给出了两个可能导致错误的原因。 ... [详细]
  • Objective C接入Sonar代码扫描
    目录技术方案环境准备扫描器配置项目配置SonarQube配置jenkins接入一些坑技术方案Sonar本身有对OC的代码扫描插件——SonarCFamily,但是是收费的。出于成本 ... [详细]
  • 多态性这个词表示有许多形式。通常,当存在类的层次结构并且通过继承相关时,会发生多态性。Objective-C多态表示对成员函数的调用将导致执行不同的函数,具体取决于调用该函数的对 ... [详细]
  • jsappsugar,基于,js,语法,定义 ... [详细]
  • UIView视图,表示屏幕上的一块矩形区域,同时处理该区域的绘制和触屏事件。一个视图也可以作为其他视图的父视图,同时决定着这些子视图的位置和大小.UIView类做了大量的工作去管理 ... [详细]
  • [好文要转]【关于block使用的5点注意事项】
    1、在使用block前需要对block指针做判空处理。不判空直接使用,一旦指针为空直接产生崩溃。if(!self.isOnlyNet){if(succBlockNUL ... [详细]
  • YOLOv7基于自己的数据集从零构建模型完整训练、推理计算超详细教程
    本文介绍了关于人工智能、神经网络和深度学习的知识点,并提供了YOLOv7基于自己的数据集从零构建模型完整训练、推理计算的详细教程。文章还提到了郑州最低生活保障的话题。对于从事目标检测任务的人来说,YOLO是一个熟悉的模型。文章还提到了yolov4和yolov6的相关内容,以及选择模型的优化思路。 ... [详细]
  • Iamtryingtomakeaclassthatwillreadatextfileofnamesintoanarray,thenreturnthatarra ... [详细]
  • 本文介绍了使用kotlin实现动画效果的方法,包括上下移动、放大缩小、旋转等功能。通过代码示例演示了如何使用ObjectAnimator和AnimatorSet来实现动画效果,并提供了实现抖动效果的代码。同时还介绍了如何使用translationY和translationX来实现上下和左右移动的效果。最后还提供了一个anim_small.xml文件的代码示例,可以用来实现放大缩小的效果。 ... [详细]
  • Linux重启网络命令实例及关机和重启示例教程
    本文介绍了Linux系统中重启网络命令的实例,以及使用不同方式关机和重启系统的示例教程。包括使用图形界面和控制台访问系统的方法,以及使用shutdown命令进行系统关机和重启的句法和用法。 ... [详细]
  • iOS 类簇及越界处理
     估计做iOS开发的朋友都遇到多一个问题,就是数组越界,-[__NSArray0objectAtIndex:]:index1beyondboundsforemptyNSArray’ ... [详细]
  • 我的iOS开发入门自学路径
    我有一个清单,列着希望在大学里完成的事。比如,学一门乐器,和朋友去旅游,搭建自己的博客,去滑翔,看各主题的书籍。其中一项是,写自己的App并且上架。去年开始,我准备完成这一项,所以 ... [详细]
author-avatar
手机用户2602933613
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有