Cocoa/Objective-C 中是否有类似通用列表的东西?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/793644/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-03 21:27:21  来源:igfitidea点击:

Is there anything like a generic list in Cocoa / Objective-C?

objective-ccocoalistdata-structuresstrong-typing

提问by TalkingCode

What I really like in C# are generic lists. A list that can contain only one type of objects. Is there something like a generic list in Cocoa/Objective-C? As far I only know NSArraywho will take a pointer to any object.

我在 C# 中真正喜欢的是泛型列表。只能包含一种类型的对象的列表。Cocoa/Objective-C 中是否有类似通用列表的东西?到目前为止,我只知道NSArray谁将获取指向任何对象的指针。

回答by Mike Abdullah

Wanting this in a Cocoa app is often a sign of a weak design.

在 Cocoa 应用程序中想要这个通常是设计薄弱的标志。

NSArrayis immutable, so it will not "take a pointer to any object" and presumably already contains the correct objects when handed to you. What I assume you're more worried about is an NSMutableArraywhere you think other parts of your code might add the wrong sort of object. But have a look at Cocoa itself; it's incredibly rare to expose a mutable array as part of a class's design.

NSArray是不可变的,因此它不会“获取指向任何对象的指针”,并且在交给您时可能已经包含正确的对象。我认为您更担心的是NSMutableArray您认为代码的其他部分可能会添加错误类型的对象。但是看看 Cocoa 本身;将可变数组作为类设计的一部分公开是非常罕见的。

Instead, you generally expose an NSArrayand a couple of methods for modifying that array. Something along the lines of:

相反,您通常会公开NSArray一些方法来修改该数组。类似的东西:

@class Foo : NSObject
- (NSArray *)bars;
- (void)addBar:(Bar *)bar;
- (void)removeBar:(Bar *)bar;
@end

This generally stops wrong objects being inserted simply by having a compiler warning, and then of course you can add assertions within -addBar:and -removeBar:if you wish too.

这通常会通过编译器警告来阻止插入错误的对象,然后当然您可以在其中添加断言-addBar:-removeBar:如果您愿意的话。

回答by Ferruccio

Objective-C doesn't support generic programming. You could always use Objective-C++ and an STL list.

Objective-C 不支持泛型编程。您始终可以使用 Objective-C++ 和 STL 列表。

回答by w-m

Generic NSArrays can be realized by subclassing NSArray, and redefining all provided methods with more restrictive ones. For example,

泛型 NSArrays 可以通过子类化来实现NSArray,并用更严格的方法重新定义所有提供的方法。例如,

- (id)objectAtIndex:(NSUInteger)index

would have to be redefined in

必须重新定义

@interface NSStringArray : NSArray

as

作为

- (NSString *)objectAtIndex:(NSUInteger)index

for an NSArray to contain only NSStrings.

使 NSArray 仅包含 NSStrings。

The created subclass can be used as a drop-in replacement and brings many useful features: compiler warnings, property access, better code creation and -completion in Xcode. All these are compile-time features, there is no need to redefine the actual implementation - NSArray's methods can still be used.

创建的子类可以用作替代品并带来许多有用的功能:编译器警告、属性访问、更好的代码创建和 Xcode 中的 -completion。所有这些都是编译时的特性,不需要重新定义实际的实现——NSArray 的方法仍然可以使用。

It's possible to automate this and boil it down to only two statements, which brings it close to languages that support generics. I've created an automation with WMGenericCollection, where templates are provided as C Preprocessor Macros.

可以将其自动化并将其归结为仅两个语句,这使其接近支持泛型的语言。我已经使用WMGenericCollection创建了一个自动化,其中模板作为 C 预处理器宏提供。

After importing the header file containing the macro, you can create a generic NSArray with two statements: one for the interface and one for the implementation. You only need to provide the data type you want to store and names for your subclasses. WMGenericCollection provides such templates for NSArray, NSDictionaryand NSSet, as well as their mutable counterparts.

导入包含宏的头文件后,您可以使用两条语句创建一个通用的 NSArray:一条用于接口,另一条用于实现。您只需要提供要存储的数据类型和子类的名称。WMGenericCollection 为NSArrayNSDictionaryNSSet以及它们的可变对应物提供了这样的模板。

回答by David Jeske

No, Objective-C does not currently support parametric typing for collection elements.

不,Objective-C 目前不支持集合元素的参数类型。

However, this topic is more complex than the question or existing answers admit..

然而,这个话题比问题或现有答案所承认的要复杂。

Parametric-Typing for collections in Objective-C would not be the same as Generics in C#/Java. For example, it is unlikely you would ever see Objective-C add the capability to assure every object added to a collection ISan NSArray type or subtype. Instead, Objective-C could (and IMO should) have the ability to assure every object in a collection CONFORMSto a protocol/interface. (i.e. that it implements a set of required methods)

Objective-C 中集合的参数类型与 C#/Java 中的泛型不同。例如,它是不太可能,你会看到过Objective-C的补充,以确保添加到集合中的每个对象的能力IS一个NSArray型或亚型。相反,Objective-C 可以(并且 IMO 应该)有能力确保集合中的每个对象符合协议/接口。(即它实现了一组必需的方法)

Why?

为什么?

Objective-C is a language built on protocol (interface) compatibility, NOT subtyping relationships. That is, objects are compatible if they have all the right methods, we don't look at or care about their actual types. In fact, looking at actual types is a very very bad practice in Obj-C and in highly discouraged. This notion is sometimes called "Duck Typing", because if it quacks like a duck, it's a duck. We don't care if it literally inherited from some specific duck or not. This prevents you from being saddled by someone elses implementation hierarchy. -- The result is that as long as an object coming out of the list has a draw:: method it works, we don't actually care if it is a subclass of some specific JimmyDrawableBase object.

Objective-C 是一种建立在协议(接口)兼容性上的语言,而不是子类型关系。也就是说,如果对象具有所有正确的方法,则对象是兼容的,我们不会查看或关心它们的实际类型。事实上,在 Obj-C 中查看实际类型是一种非常糟糕的做法,并且非常不鼓励。这个概念有时被称为“鸭子打字”,因为如果它像鸭子一样嘎嘎叫,那就是鸭子。我们不在乎它是否真的从某个特定的鸭子继承下来。这可以防止您被其他人的实现层次结构所困扰。-- 结果是,只要从列表中出来的对象有一个 draw:: 方法就可以工作,我们实际上并不关心它是否是某个特定 JimmyDrawableBase 对象的子类。

This not only makes code more reusable, but it also encourages a slightly different (more functional?) type of problem decomposition, because you can't rely on objects being derived from a given base class and thus having a bunch of your base-class implementation forced into them.

这不仅使代码更可重用,而且还鼓励稍微不同(更实用?)类型的问题分解,因为您不能依赖从给定基类派生的对象,从而拥有一堆基类强制执行。

I personally think it would be nicefor the Obj-C compiler to have parametric checking of PROTOCOL*CONFORMANCE*. That is, to make a NSMutableArray which requires all objects placed in it conform to a given protocol (i.e. have a given set of required methods).

我个人认为Obj-C 编译器对PROTOCOL*CONFORMANCE*进行参数检查会很好。也就是说,使 NSMutableArray 要求放置在其中的所有对象符合给定的协议(即具有给定的一组所需方法)。

Sometimes even this more-flexible protocol-conformance checking is resisted by dynamic programming folks, and with sound reasons. Programmers often have a way of over-specifying conformance requirements.

有时,即使是这种更灵活的协议一致性检查也会遭到动态编程人员的抵制,并且有充分的理由。程序员通常有一种过度指定一致性要求的方法。

For example, you might require a list contain objects conforming to the NSArray protocol/interface, but you might ACTUALLYonly call two of those methods. This is over-conformance. Someone who wishes to stick a compatible item in your array is forced to implement a ton of methods you are not actually calling -- at least not yet (see next).

例如,你可能需要一个列表包含符合NSArray的协议/接口的对象,但你可能ACTUALLY只调用两种这些方法。这是过度遵守。希望在您的数组中粘贴兼容项的人被迫实现大量您实际上并未调用的方法——至少现在还没有(见下文)。

Google Go tries to solve this problem by inferring structural compatibility. That is, if you call draw() on items coming out of a list, then the compiler assures everything going into a list contains a draw() method. If it does not contain a draw() method, it's a compiler error to put it into the list. This prevents the code from simply causing the same error to occur at runtime. The problem with this is that it only works for whole-program compilation. If Google-Go could compile modular DLLs (which it can't), then it would run into the problem that there isn't a way for me to say objects in the list need to support a specific interface of three methods, even though I'm not calling them today, because I might call them in the future.

Google Go 试图通过推断结构兼容性来解决这个问题。也就是说,如果您对列表中的项目调用 draw(),那么编译器会确保进入列表的所有内容都包含一个 draw() 方法。如果它不包含 draw() 方法,则将其放入列表是编译器错误。这可以防止代码在运行时简单地导致相同的错误发生。问题在于它仅适用于整个程序编译。如果 Google-Go 可以编译模块化 DLL(它不能),那么它会遇到一个问题,即我无法说列表中的对象需要支持三种方法的特定接口,即使我今天不打电话给他们,因为我将来可能会打电话给他们

Between those two solution likes the tradeoff and the truth.

在这两种解决方案之间进行权衡和真相。

Personally, I would like to see Objective-C add parametric protocol conformance, so I could ask the compiler to assure the contents of a particular collection always conform to a given set of protocols.

就我个人而言,我希望 Objective-C 添加参数协议一致性,因此我可以要求编译器确保特定集合的内容始终符合给定的一组协议。

I would also like the compiler to help me avoid over-conformance. If I'm not calling methods in those protocols on objects, it should generate errors/warnings telling me so. If I want to keep them in the protocol even though I'm not using them, I should have to explicitly make a declaration for each method in the protocol that it "might be used in the future, so elements all need to supply it now". This at least makes the process of over-conformance require MORE work, instead of Java/C# where it requires less work.

我还希望编译器帮助我避免过度一致性。如果我没有在对象上调用这些协议中的方法,它应该生成错误/警告告诉我。如果我想将它们保留在协议中,即使我不使用它们,我也必须为协议中的每个方法明确声明它“可能在未来使用,因此元素现在都需要提供它”。这至少使得过度一致性的过程需要更多的工作,而不是 Java/C# 需要更少的工作。