在Objective C中定义不可变类的最佳方法

时间:2023-01-15 15:36:13

I am a newbie in Objective C and I was wondering what is the best way to define an immutable class in Objective-C (like NSString for example).

我是Objective-C的新手,我想知道在Objective-C中定义不可变类的最好方法是什么(比如NSString)。

I want to know what are the basic rules one has to follow to make a class immutable.

我想知道要使类成为不可变的基本规则是什么。

I think that :

我认为:

  • setters shouldn't be provided
  • setter不应该提供
  • if properties are used, they should be readonly
  • 如果使用了属性,那么它们应该是只读的
  • to "disable" Key Value Coding , accessInstanceVariablesDirectly must be override and return NO
  • 要“禁用”键值编码,accessinstancevariablesdirect必须重写并返回NO

Did I forget something ?

我忘记什么了吗?

Thanks

谢谢

2 个解决方案

#1


13  

The first and foremost thing you should do is to include usage comments in your .h file that explain that this is an immutable class, along with the class's purpose and general usage guidance. Far too often people go to great lengths to try to "enforce" with the compiler what could be achieved by just informing the caller.

您应该做的第一件也是最重要的事情是在.h文件中包含用法注释,说明这是一个不可变类,以及类的用途和一般用法指导。很多时候,人们总是不遗余力地试图用编译器“强制执行”,只要通知调用者就可以实现。

You should certainly not provide public setters or readwrite properties if you intend the class to be immutable (but of course you should provide private setters so that you can use accessors within the class; you should always avoid, even internally, messing with ivars directly except in a few places). I guess you could add your accessInstanceVariablesDirectly override if you saw this as a likely error on the part of the caller.

如果您希望类是不可变的,那么当然不应该提供公共setter或readwrite属性(但是当然应该提供私有setter,以便在类中使用访问器;你应该避免直接使用ivars(除了一些地方),即使是在内部。我想你可以添加accessinstancevariablesdirect覆盖,如果您认为这是调用者的一个可能的错误。

But the key to understanding Objective-C is to understand and embrace the fact that the caller is not the enemy. The called code does not need to be "protected" from the caller. The caller needs to be protected from likely error. Everyone is on the same side here; caller and called want the program to work.

但是理解Objective-C的关键是理解并接受调用者不是敌人的事实。被调用的代码不需要受到调用者的“保护”。调用者需要被保护以避免可能的错误。每个人都站在同一边;调用者和调用者希望程序工作。

The caller is the customer and should be treated as such. The customer is not always right, but the customer is always the customer. Sometimes that means protecting the customer from himself if there is an easy mistake he might make. NSAssert() is particularly useful for that. And providing public setters to an immutable class is almost tricking the caller into making a mistake, so that would be bad for everyone.

打电话的人是顾客,应该这样对待。顾客并不总是对的,但是顾客总是顾客。有时,这意味着如果客户可能犯一个很容易犯的错误,要保护他自己。NSAssert()对此特别有用。为一个不变的类提供公共setter几乎是在欺骗调用者犯错误,所以这对每个人都不好。

In any case, you shouldn't make your class overly complex to try to enforce immutability. The caller can almost (*) always violate encapsulation by accessing the struct directly (object->ivar). The caller would be foolish to do so, but you would be even more foolish to try to prevent it. Note the immutability, hide your setters and mark your properties readonly, and in almost all cases you should be fine.

在任何情况下,您都不应该让您的类过于复杂,以试图强制执行不变性。调用者可以通过直接访问结构体(对象->ivar)几乎总是(*)违反封装。打电话的人这样做是愚蠢的,但是你要阻止这种行为就更愚蠢了。注意不可变性,隐藏setter和标记属性只读,在几乎所有情况下都应该没问题。

(*) Yes, it's possible to even more hide your data by nesting a private struct/object as an ivar, but then the caller can still modify the data with pointer arithmetic so it's still not "enforced." Always ask yourself what problem you're really trying to solve.

(*)是的,可以通过将私有结构/对象嵌套为ivar来隐藏数据,但是调用者仍然可以使用指针算法修改数据,因此它仍然不是“强制的”。总是问自己你真正想解决的问题是什么。

#2


6  

I believe they way I'd accomplish this is to have the header file contain only the publicly needed information. The rest would go in to the source file to limit possible override exposure.

我相信他们的方法是让头文件只包含公开需要的信息。其余部分将进入源文件,以限制可能的覆盖暴露。

Since Objective-C apparently has no definitive way of defining a class as final (sealed, etc), everything you'd be able to do isn't really all encompassing.

由于Objective-C显然没有确定的方法来定义一个类为final(密封的,等等),所以你所能做的并不是全部包含。

I've long ago came to the conclusion that you really can't use Objective-C like you'd use Java, C++ or C#. Objective-C is simply too different. In fact I believe there are drastic paradigm differences such as static vs. dynamic method dispatch/calls.

我很久以前就得出结论,你不能像使用Java、c++或c#那样使用Objective-C。Objective-C太不一样了。事实上,我认为有一些极端的范式差异,比如静态和动态方法分派/调用。

The reason I mention this is because perhaps no class in Objective-C is truly final. Perhaps this is by language design and not something you should try to get around. If you do, you'd ultimately needlessly complicate your code.

我提到这一点的原因是也许Objective-C中没有任何类是最终的。也许这是由于语言设计的缘故,而不是你应该尝试去做的事情。如果您这样做,您最终将不必要地使代码复杂化。

#1


13  

The first and foremost thing you should do is to include usage comments in your .h file that explain that this is an immutable class, along with the class's purpose and general usage guidance. Far too often people go to great lengths to try to "enforce" with the compiler what could be achieved by just informing the caller.

您应该做的第一件也是最重要的事情是在.h文件中包含用法注释,说明这是一个不可变类,以及类的用途和一般用法指导。很多时候,人们总是不遗余力地试图用编译器“强制执行”,只要通知调用者就可以实现。

You should certainly not provide public setters or readwrite properties if you intend the class to be immutable (but of course you should provide private setters so that you can use accessors within the class; you should always avoid, even internally, messing with ivars directly except in a few places). I guess you could add your accessInstanceVariablesDirectly override if you saw this as a likely error on the part of the caller.

如果您希望类是不可变的,那么当然不应该提供公共setter或readwrite属性(但是当然应该提供私有setter,以便在类中使用访问器;你应该避免直接使用ivars(除了一些地方),即使是在内部。我想你可以添加accessinstancevariablesdirect覆盖,如果您认为这是调用者的一个可能的错误。

But the key to understanding Objective-C is to understand and embrace the fact that the caller is not the enemy. The called code does not need to be "protected" from the caller. The caller needs to be protected from likely error. Everyone is on the same side here; caller and called want the program to work.

但是理解Objective-C的关键是理解并接受调用者不是敌人的事实。被调用的代码不需要受到调用者的“保护”。调用者需要被保护以避免可能的错误。每个人都站在同一边;调用者和调用者希望程序工作。

The caller is the customer and should be treated as such. The customer is not always right, but the customer is always the customer. Sometimes that means protecting the customer from himself if there is an easy mistake he might make. NSAssert() is particularly useful for that. And providing public setters to an immutable class is almost tricking the caller into making a mistake, so that would be bad for everyone.

打电话的人是顾客,应该这样对待。顾客并不总是对的,但是顾客总是顾客。有时,这意味着如果客户可能犯一个很容易犯的错误,要保护他自己。NSAssert()对此特别有用。为一个不变的类提供公共setter几乎是在欺骗调用者犯错误,所以这对每个人都不好。

In any case, you shouldn't make your class overly complex to try to enforce immutability. The caller can almost (*) always violate encapsulation by accessing the struct directly (object->ivar). The caller would be foolish to do so, but you would be even more foolish to try to prevent it. Note the immutability, hide your setters and mark your properties readonly, and in almost all cases you should be fine.

在任何情况下,您都不应该让您的类过于复杂,以试图强制执行不变性。调用者可以通过直接访问结构体(对象->ivar)几乎总是(*)违反封装。打电话的人这样做是愚蠢的,但是你要阻止这种行为就更愚蠢了。注意不可变性,隐藏setter和标记属性只读,在几乎所有情况下都应该没问题。

(*) Yes, it's possible to even more hide your data by nesting a private struct/object as an ivar, but then the caller can still modify the data with pointer arithmetic so it's still not "enforced." Always ask yourself what problem you're really trying to solve.

(*)是的,可以通过将私有结构/对象嵌套为ivar来隐藏数据,但是调用者仍然可以使用指针算法修改数据,因此它仍然不是“强制的”。总是问自己你真正想解决的问题是什么。

#2


6  

I believe they way I'd accomplish this is to have the header file contain only the publicly needed information. The rest would go in to the source file to limit possible override exposure.

我相信他们的方法是让头文件只包含公开需要的信息。其余部分将进入源文件,以限制可能的覆盖暴露。

Since Objective-C apparently has no definitive way of defining a class as final (sealed, etc), everything you'd be able to do isn't really all encompassing.

由于Objective-C显然没有确定的方法来定义一个类为final(密封的,等等),所以你所能做的并不是全部包含。

I've long ago came to the conclusion that you really can't use Objective-C like you'd use Java, C++ or C#. Objective-C is simply too different. In fact I believe there are drastic paradigm differences such as static vs. dynamic method dispatch/calls.

我很久以前就得出结论,你不能像使用Java、c++或c#那样使用Objective-C。Objective-C太不一样了。事实上,我认为有一些极端的范式差异,比如静态和动态方法分派/调用。

The reason I mention this is because perhaps no class in Objective-C is truly final. Perhaps this is by language design and not something you should try to get around. If you do, you'd ultimately needlessly complicate your code.

我提到这一点的原因是也许Objective-C中没有任何类是最终的。也许这是由于语言设计的缘故,而不是你应该尝试去做的事情。如果您这样做,您最终将不必要地使代码复杂化。