Objective c 当可以从实例外部设置IVAR/属性时,为什么要创建自定义init?
我正在读一本Objective-C的书,我有一个问题,这本书似乎没有真正回答 假设我有两个定制的类 第一个类称为Objective c 当可以从实例外部设置IVAR/属性时,为什么要创建自定义init?,objective-c,variables,inheritance,methods,init,Objective C,Variables,Inheritance,Methods,Init,我正在读一本Objective-C的书,我有一个问题,这本书似乎没有真正回答 假设我有两个定制的类 第一个类称为ClassA。它当然有.h和.m文件。第二个类称为ClassB。它也有.h和.m文件 在代码的某个地方,“ClassA”有以下方法: -(IBAction)displaySomeText:(id)sender { ClassB *myNumber = [[ClassB alloc]init]; NSString *numberString = [myNumber s
ClassA
。它当然有.h和.m文件。第二个类称为ClassB
。它也有.h和.m文件
在代码的某个地方,“ClassA”有以下方法:
-(IBAction)displaySomeText:(id)sender {
ClassB *myNumber = [[ClassB alloc]init];
NSString *numberString = [myNumber storedNumberAsString];
// storedNumberAsString is just a method that returns a string object that holds
// myVariable.
[textView insertText:numberString];
//textView is a object I created that just displays some text on screen.
[myNumber release];
}
这本书告诉我ClassB
应该有一个方法:
-(id)init {
[super init]; //I know why this is done, the book explains it well.
myVariable = 42; // I created this variable already in the ClassB .h file
return self;
}
现在,当我在Interface Builder中单击我连接的按钮等时,显示的数字是42
我的问题是,如果我可以在ClassA
的方法中执行以下操作,为什么我必须为ClassB
创建-(id)init
方法:
-(IBAction)displaySomeText:(id)sender {
ClassB *myNumber = [[ClassB alloc]init];
myNumber.myVariable = 42; //I just do this to skip the -(id)init method.
NSString *numberString = [myNumber storedNumberAsString];
[textView insertText:numberString];
[myNumber release];
}
执行此操作时,它仍然显示相同的值:
42
。我可以把它换成我喜欢的任何东西。那么,为什么不直接使用继承自NSObject
的init
,并使用简单的方法myNumber.myVariable=42
?假设实例变量的值比整数更复杂。假设它涉及从文件中读取字符串,或者通过网络获取一些信息,或者只是做一些算术运算。在这种情况下,让ClassA
负责正确设置该值是没有意义的。这将打破一开始让单独的类变得有用的规则
在这个非常简单的例子中,您是对的,可能没有理由为ClassB
使用自定义初始值设定项,但一般来说,类本身应该负责正确设置其状态。将责任强加给其他类意味着其他类需要了解第一类的内部,这意味着这两个类之间的耦合可能过于紧密
在某些情况下,ivar的值可能是一条只有
ClassA
知道的信息,或者需要基于此类信息进行计算。然后,您应该为接收该值的ClassB
创建自定义初始值设定项,例如,-(id)initWithInteger:
这将成为,然后您将覆盖-[ClassB init]
以合理的默认值调用它。假设实例变量的值比整数更复杂。假设它涉及从文件中读取字符串,或者通过网络获取一些信息,或者只是做一些算术运算。在这种情况下,让ClassA
负责正确设置该值是没有意义的。这将打破一开始让单独的类变得有用的规则
在这个非常简单的例子中,您是对的,可能没有理由为ClassB
使用自定义初始值设定项,但一般来说,类本身应该负责正确设置其状态。将责任强加给其他类意味着其他类需要了解第一类的内部,这意味着这两个类之间的耦合可能过于紧密
在某些情况下,ivar的值可能是一条只有
ClassA
知道的信息,或者需要基于此类信息进行计算。然后,您应该为ClassB
创建一个自定义初始值设定项,该初始值设定项接收该值,例如,-(id)initWithInteger:
这将成为,然后您将覆盖-[ClassB init]
以使用一些合理的默认值调用它。如果ClassB实例不需要初始化任何内容(除了nil/zero之外),您不需要为ClassB创建显式的init
方法。在这种情况下,问题是将myVariable
设置为42
是否是ClassB的,或者myVariable
是否只是ClassB中可以设置为任何值的字段
也就是说,问题是概念性的,而不是物理意义上的。如果值
42
“在概念上属于”ClassB,那么ClassB应该有一个init
方法来设置它。如果该特定值对ClassA的意义大于对ClassB的意义,那么ClassA的某个方法应该设置它。如果您这样做“错误”代码仍然可以很好地工作,但是您的设计稍微不那么优雅,稍微不那么可扩展,稍微不那么健壮。如果ClassB的实例不需要初始化任何东西(除了nil/zero),您不需要为ClassB创建显式的init
方法。在这种情况下,问题是将myVariable
设置为42
是否是ClassB的,或者myVariable
是否只是ClassB中可以设置为任何值的字段
也就是说,问题是概念性的,而不是物理意义上的。如果值
42
“在概念上属于”ClassB,那么ClassB应该有一个init
方法来设置它。如果该特定值对ClassA的意义大于对ClassB的意义,那么ClassA的某个方法应该设置它。如果您这样做“错误”代码仍然可以很好地工作,但是您的设计稍微不那么优雅,稍微不那么可扩展,稍微不那么健壮。这是一个棘手的问题。我是在构造师(初始值设定者)之后“长大”才想到这一点的运行时,对象应该准备就绪。您应该能够安全地调用它上的任何方法。因此,您需要在构造函数中设置0不是有效值的任何实例变量。我喜欢在它们有0值时设置它们,只是为了保持理智,因为我永远不想知道我所使用的每种语言的详细信息k,比如它们是否自动将实例变量初始化为0
但是,有些参数不支持初始化某些变量
- 初始化很复杂,例如加载文件或从网络获取数据。是否要保留