总结一下学习Designated Initializer的过程
来源:互联网 发布:淘宝动态评分怎么提升 编辑:程序博客网 时间:2024/05/30 02:25
其实我也是在看别的代码时无意中搜了一下initWithCoder这个方法,结果就引导 Designated Initializer那里去了。既然来了就弄懂吧,反正早晚都是要了解的,你看,这就是没有系统学习的方式,看到哪学到哪,不过这有一个好处,就是知道为什么缘由,不像有些教程那样,没有任何前戏直接就讲,我受不了。
在学些过程中主要参考了下面的两篇文章:
正确编写Designated Initializer的几个原则
How To: Objective C Initializer Patterns
这两篇文章解释的很清楚,尤其是how to那篇,还形象的画了调用的顺序图,看起来更加直观一些,还真是肯花时间啊,不过我想他画完图之后自己也会更加深刻了,那句话怎么说来着:送人玫瑰,自己手也香。所以我也来好好的总结一下,顺便加深自己的印象。
其实我要做的就是把他们在文章说的用代码验证一下。
我创建了一命令行的工程,在里面使用了xtrace,使用的目的是跟踪打印各个类的调用顺序。使用xtrace的方法就不在这里说明了,搜吧。
主要文件见下面:
//// main.m// my-test-designate-initializer//// Created by ChrisBluez on 9/23/16.// Copyright © 2016 ChrisBluez. All rights reserved.//#import <Foundation/Foundation.h>#import "TestInitView.h"#import "SubTestInitView.h"int main(int argc, const char * argv[]) { @autoreleasepool { // insert code here... [Xtrace includeMethods:@"^init"]; [Xtrace traceClass:[NSView class]]; [Xtrace traceClass:[TestInitView class]]; [Xtrace traceClass:[SubTestInitView class]]; [Xtrace traceClass:[NSObject class]]; TestInitView *tv = [[TestInitView alloc] initWithFrame:CGRectZero andName:@" "]; tv = tv; TestInitView *tv2 = [[TestInitView alloc] initWithFrame:CGRectZero]; NSLog(@"Hello, World!"); NSLog(@"i am new %@.",[NSDate date]); } return 0;}
//// TestInitView.h// my-test-designate-initializer//// Created by ChrisBluez on 9/24/16.// Copyright © 2016 ChrisBluez. All rights reserved.//#import <Cocoa/Cocoa.h>@interface TestInitView : NSView//Designated Initializer- (instancetype)initWithFrame:(NSRect)frameRect andName:(NSString *)name;@end
//// TestInitView.m// my-test-designate-initializer//// Created by ChrisBluez on 9/24/16.// Copyright © 2016 ChrisBluez. All rights reserved.//#import "TestInitView.h"@implementation TestInitView- (void)drawRect:(NSRect)dirtyRect { [super drawRect:dirtyRect]; // Drawing code here.}//Designated Initializer- (instancetype)initWithFrame:(NSRect)frameRect andName:(NSString *)name{ if(self == [super init]) //if(self == [super initWithFrame:frameRect]) { //self.name = name; } return self;}/*//Overriding super class Designated Initializer- (id)initWithFrame:(NSRect)frameRect{ return [self initWithFrame:frameRect andName:@" "];} */@end
//// SubTestInitView.h// my-test-designate-initializer//// Created by ChrisBluez on 9/24/16.// Copyright © 2016 ChrisBluez. All rights reserved.//#import "TestInitView.h"@interface SubTestInitView : TestInitView@end
//// SubTestInitView.m// my-test-designate-initializer//// Created by ChrisBluez on 9/24/16.// Copyright © 2016 ChrisBluez. All rights reserved.//#import "SubTestInitView.h"@implementation SubTestInitView- (void)drawRect:(NSRect)dirtyRect { [super drawRect:dirtyRect]; // Drawing code here.}@end
此时此刻的文件实现目的是看看重新定义了子类的Designated Initiazlizer后,(1)没有override父类的Designated Initializer 和(2)没有在子类新定义的Designated Initializer中调用父类的Designated Initializer的情况下,使用子类Instance一个变量是什么样的顺序,原谅我在中文中加载了单词,原因是我也不知道该怎么翻译好。Instance的意思是说定义一个指定类型的变量,这个描述的话是在有点绕口,就当它在文中是个宏吧。
简单介绍一下这几个文件的关系,其实也能看出来TestInitView是继承于NSView的,在TestInitView.m中定义了一个新的Designated Initializer,但是却没有override父类的Designated Initializer,因为被我注释掉了。并且新定义 Designated Initializer也没有调用父类的Designated Initializer,它存在两个问题。
新定义的Designated Initializer是
//Designated Initializer- (instancetype)initWithFrame:(NSRect)frameRect andName:(NSString *)name{ if(self == [super init]) //if(self == [super initWithFrame:frameRect]) { //self.name = name; } return self;}
SubTestInitView在这时没有使用。
main.m中使用TestInitView 初始化了2个实例,但是使用的方法不一样。
TestInitView *tv = [[TestInitView alloc] initWithFrame:CGRectZero andName:@" "];
是企图通过使用自己Designated Initializer来初始化一个实例变量。
还有一个,它企图使用父类的Designated Initializer来实例化一个变量
TestInitView *tv2 = [[TestInitView alloc] initWithFrame:CGRectZero];
下面看看他的调用顺序,注意他们都是错误的。第1个实例化的顺序错了,第2个就更错了,缺少很多中间的过程。
2016-09-24 17:11:37.428 my-test-designate-initializer[2331:216606] Xtrace: Tracing NSObject will not trace all classes| From: main| [<TestInitView 0x10020fc00> initWithFrame:{{0, 0}, {0, 0}} andName:@" "]| [<TestInitView 0x10020fc00>/NSView init]| [<TestInitView 0x10020fc00>/NSView initWithFrame:{{0, 0}, {0, 0}}]| [<TestInitView 0x10020fc00>/NSResponder init]| -> <TestInitView 0x10020fc00> (init)| -> <TestInitView 0x10020fc00> (initWithFrame:)| -> <TestInitView 0x10020fc00> (init)| -> <TestInitView 0x10020fc00> (initWithFrame:andName:)| From: main| [<TestInitView 0x10030caf0>/NSView initWithFrame:{{0, 0}, {0, 0}}]| [<TestInitView 0x10030caf0>/NSResponder init]| -> <TestInitView 0x10030caf0> (init)| -> <TestInitView 0x10030caf0> (initWithFrame:)2016-09-24 17:11:37.429 my-test-designate-initializer[2331:216606] Hello, World!2016-09-24 17:11:37.431 my-test-designate-initializer[2331:216606] i am new 2016-09-24 09:11:37 +0000.Program ended with exit code: 0
下面来奉上正确的代码。
首先需要修改TestInitView.m
1.在新定义的Designated Initializer中调用父类的Designated Initializer;
2.重新定义父类的Designated Initializer,并且调用1中新定义的Designated Initiazlier;
修改后的代码为:
//// TestInitView.m// my-test-designate-initializer//// Created by ChrisBluez on 9/24/16.// Copyright © 2016 ChrisBluez. All rights reserved.//#import "TestInitView.h"@implementation TestInitView- (void)drawRect:(NSRect)dirtyRect { [super drawRect:dirtyRect]; // Drawing code here.}//Designated Initializer- (instancetype)initWithFrame:(NSRect)frameRect andName:(NSString *)name{ //if(self == [super init]) if(self == [super initWithFrame:frameRect]) { //self.name = name; } return self;}//Overriding super class Designated Initializer- (id)initWithFrame:(NSRect)frameRect{ return [self initWithFrame:frameRect andName:@" "];}@end
然后再重新运行,查看console中的打印结果
2016-09-24 17:20:19.942 my-test-designate-initializer[2356:223925] Xtrace: Tracing NSObject will not trace all classes| From: main| [<TestInitView 0x100200710> initWithFrame:{{0, 0}, {0, 0}} andName:@" "]| [<TestInitView 0x100200710>/NSView initWithFrame:{{0, 0}, {0, 0}}]| [<TestInitView 0x100200710>/NSResponder init]| -> <TestInitView 0x100200710> (init)| -> <TestInitView 0x100200710> (initWithFrame:)| -> <TestInitView 0x100200710> (initWithFrame:andName:)| From: main| [<TestInitView 0x100207d60> initWithFrame:{{0, 0}, {0, 0}}]| [<TestInitView 0x100207d60> initWithFrame:{{0, 0}, {0, 0}} andName:@" "]| [<TestInitView 0x100207d60>/NSView initWithFrame:{{0, 0}, {0, 0}}]| [<TestInitView 0x100207d60>/NSResponder init]| -> <TestInitView 0x100207d60> (init)| -> <TestInitView 0x100207d60> (initWithFrame:)| -> <TestInitView 0x100207d60> (initWithFrame:andName:)| -> <TestInitView 0x100207d60> (initWithFrame:)2016-09-24 17:20:19.944 my-test-designate-initializer[2356:223925] Hello, World!2016-09-24 17:20:19.946 my-test-designate-initializer[2356:223925] i am new 2016-09-24 09:20:19 +0000.Program ended with exit code: 0
其中,NSResponder是NSView的父类,NSObject是NSResponder的父类。
对比两种结果就知道哪里有错误了。错误的实现Desigated Initializer和相关的Initializer带来的后果就是1.漏掉了某些期望被调用的Initializer,2调用顺序错误,3就是1和2都有。
最后不要脸的补充一下,这篇文章是目前我写的比较有技术含量的一篇,它集代码,运行结果,参考链接为一体。
再接再励。
我现在老丈人家,等会吃完饭跟媳妇回家再继续研究。
你们等着,我要学ios挣钱。
- 总结一下学习Designated Initializer的过程
- designated initializer
- 正确编写Designated Initializer的几个原则
- 正确编写Designated Initializer的几个原则
- 正确编写Designated Initializer的几个原则
- 正确编写Designated Initializer的几个原则
- ios: Designated Initializer
- designated initializer:一种特殊的结构体初始化方法
- C语言的定制初始化(designated initializer)
- NS_DESIGNATED_INITIALIZER 正确编写Designated Initializer的几个原则
- swift - Designated Initializer & Convenience Initializers
- 指定初始化器designated initializer的意义以及[super init...]意义的个人心得
- CoreData: error: Failed to call designated initializer on NSManagedObject 的解决方法
- (iOS)Storyboard 与 initWithCoder -- designated initializer小结
- Failed to call designated initializer on NSManagedObject class 'ClassName'.
- Effective Objective-C 2.0: Item 16:Designated Initializer
- iOS: 聊聊 Designated Initializer(指定初始化函数)
- iOS: 聊聊 Designated Initializer(指定初始化函数)
- 前端开发 环境搭建
- Shell下的作业管理
- LeetCode[230] Kth Smallest Element in a BST
- Deepin搭建Qt5开发环境
- codeforces 719C Efim and Strange Grade (复杂模拟)
- 总结一下学习Designated Initializer的过程
- 简单的透明shader
- Ubuntu 14.04 设置静态IP地址全攻略
- Java 文件复制 基于字节流数据传输
- SpringMVC 的配置文件实例
- 面向对象基础部分
- 【备忘】【No2】2016年最新云计算视频教程hadoop大数据实战开发
- Longest Substring Without Repeating Characters
- 安卓融云聊天