Objective-C 中有强类型集合吗?

发布于 2024-07-19 17:45:39 字数 222 浏览 9 评论 0原文

我是 Mac/iPhone 编程和 Objective-C 的新手。 在 C# 和 Java 中,我们有“泛型”,即其成员只能是声明的类型的集合类。 例如,在 C#

Dictionary

中只能包含整数键和 MyCustomObject 类型的值。 Objective-C 中是否存在类似的机制?

I'm new to Mac/iPhone programming and Objective-C. In C# and Java we have "generics", collection classes whose members can only be of the type declared. For example, in C#

Dictionary<int, MyCustomObject>

can only contain keys that are integers and values that are of type MyCustomObject. Does a similar mechanism exist in Objective-C?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(11

久伴你 2024-07-26 17:45:39

在 Xcode 7 中,Apple 向 Objective-C 引入了“轻量级泛型”。 在 Objective-C 中,如果存在类型不匹配,它们将生成编译器警告。

NSArray<NSString*>* arr = @[@"str"];

NSString* string = [arr objectAtIndex:0];
NSNumber* number = [arr objectAtIndex:0]; // Warning: Incompatible pointer types initializing 'NSNumber *' with an expression of type 'NSString *'

在 Swift 代码中,它们会产生编译器错误:

var str: String = arr[0]
var num: Int = arr[0] //Error 'String' is not convertible to 'Int'

轻量级泛型旨在与 NSArray、NSDictionary 和 NSSet 一起使用,但您也可以将它们添加到您自己的类中:

@interface GenericsTest<__covariant T> : NSObject

-(void)genericMethod:(T)object;

@end

@implementation GenericsTest

-(void)genericMethod:(id)object {}

@end

Objective-C 的行为将像以前一样,但会出现编译器警告。

GenericsTest<NSString*>* test = [GenericsTest new];

[test genericMethod:@"string"];
[test genericMethod:@1]; // Warning: Incompatible pointer types sending 'NSNumber *' to parameter of type 'NSString *'

但 Swift 会完全忽略 Generic 信息。 (在 Swift 3+ 中不再如此。)

var test = GenericsTest<String>() //Error: Cannot specialize non-generic type 'GenericsTest'

除了这些 Foundation 集合类之外,Swift 还会忽略 Objective-C 轻量级泛型。 使用轻量级泛型的任何其他类型都会导入到 Swift 中,就像它们未参数化一样。

与 Objective-C API 交互

In Xcode 7, Apple has introduced 'Lightweight Generics' to Objective-C. In Objective-C, they will generate compiler warnings if there is a type mismatch.

NSArray<NSString*>* arr = @[@"str"];

NSString* string = [arr objectAtIndex:0];
NSNumber* number = [arr objectAtIndex:0]; // Warning: Incompatible pointer types initializing 'NSNumber *' with an expression of type 'NSString *'

And in Swift code, they will produce a compiler error:

var str: String = arr[0]
var num: Int = arr[0] //Error 'String' is not convertible to 'Int'

Lightweight Generics are intended to be used with NSArray, NSDictionary and NSSet, but you can also add them to your own classes:

@interface GenericsTest<__covariant T> : NSObject

-(void)genericMethod:(T)object;

@end

@implementation GenericsTest

-(void)genericMethod:(id)object {}

@end

Objective-C will behave like it did before with compiler warnings.

GenericsTest<NSString*>* test = [GenericsTest new];

[test genericMethod:@"string"];
[test genericMethod:@1]; // Warning: Incompatible pointer types sending 'NSNumber *' to parameter of type 'NSString *'

but Swift will ignore the Generic information completely. (No longer true in Swift 3+.)

var test = GenericsTest<String>() //Error: Cannot specialize non-generic type 'GenericsTest'

Aside from than these Foundation collection classes, Objective-C lightweight generics are ignored by Swift. Any other types using lightweight generics are imported into Swift as if they were unparameterized.

Interacting with Objective-C APIs

情绪操控生活 2024-07-26 17:45:39

这个答案已经过时,但仍然具有历史价值。 从 Xcode 7 开始,Connor 在 2015 年 6 月 8 日的回答更加准确。


不,Objective-C 中没有泛型,除非您想在自己的自定义集合类中使用 C++ 模板(我强烈反对)。

Objective-C 具有动态类型功能,这意味着运行时不关心对象的类型,因为所有对象都可以接收消息。 当您将对象添加到内置集合时,它们将被视为 id 类型。 但不用担心,只需像平常一样向这些对象发送消息即可; 它将正常工作(除非集合中的一个或多个对象不响应您发送的消息)。

Java 和 C# 等语言需要泛型,因为它们是强大的静态类型语言。 与 Objective-C 的动态类型功能完全不同。

This answer is outdated but remains for historical value. As of Xcode 7, Connor's answer from Jun 8 '15 is more accurate.


No, there are no generics in Objective-C unless you want to use C++ templates in your own custom collection classes (which I strongly discourage).

Objective-C has dynamic typing as a feature, which means that the runtime doesn't care about the type of an object since all objects can receive messages. When you add an object to a built-in collection, they are just treated as if they were type id. But don't worry, just send messages to those objects like normal; it will work fine (unless of course one or more of the objects in the collection don't respond to the message you are sending).

Generics are needed in languages such as Java and C# because they are strong, statically typed languages. Totally different ballgame than Objective-C's dynamic typing feature.

听你说爱我 2024-07-26 17:45:39

不,但为了更清楚,你可以用你想要存储的对象类型来注释它,我已经看到当你现在需要在 Java 1.4 中编写一些东西时这样做了几次)例如:

NSMutableArray* /*<TypeA>*/ arrayName = ....

NSDictionary* /*<TypeA, TypeB>*/ dictionaryName = ...

No, but to make it clearer you can comment it with the type of object you want to store, I've seen this done a few times when you need to write something in Java 1.4 nowadays) e.g.:

NSMutableArray* /*<TypeA>*/ arrayName = ....

or

NSDictionary* /*<TypeA, TypeB>*/ dictionaryName = ...
醉酒的小男人 2024-07-26 17:45:39

这是在 Xcode 7 中发布的 (最后!)

请注意,在 Objective C 代码中,这只是编译时检查; 仅将错误的类型放入集合或分配给类型化属性就不会出现运行时错误。

声明:

@interface FooClass <T> : NSObject
@property (nonatomic) T prop;
@end

使用:

FooClass<NSString *> *foo = [[FooClass alloc] init];
NSArray<FooClass<NSString *> *> *fooAry = [NSArray array];

小心那些 *

This was released in Xcode 7 (finally!)

Note that in Objective C code, it's just a compile-time check; there will be no run-time error just for putting the wrong type into a collection or assigning to a typed property.

Declare:

@interface FooClass <T> : NSObject
@property (nonatomic) T prop;
@end

Use:

FooClass<NSString *> *foo = [[FooClass alloc] init];
NSArray<FooClass<NSString *> *> *fooAry = [NSArray array];

Be careful about those *s.

初心未许 2024-07-26 17:45:39

Objective-C 中没有泛型。

来自文档

数组是对象的有序集合。 Cocoa 提供了几个数组类,NSArray、NSMutableArray(NSArray 的子类)和 NSPointerArray。

There are no generics in Objective-C.

From the Docs

Arrays are ordered collections of objects. Cocoa provides several array classes, NSArray, NSMutableArray (a subclass of NSArray), and NSPointerArray.

抚笙 2024-07-26 17:45:39

Apple 在 XCode 7 中向 ObjC 添加了泛型:

@property NSArray<NSDate *>* dates;
- (NSArray<NSDate *> *)datesBeforeDate:(NSDate *)date;
- (void)addDatesParsedFromTimestamps:(NSArray<NSString *> *)timestamps;

请参见此处:
https: //developer.apple.com/library/prerelease/mac/documentation/Swift/Conceptual/BuildingCocoaApps/WorkingWithCocoaDataTypes.html#//apple_ref/doc/uid/TP40014216-CH6-ID61

Apple has added generics to ObjC in XCode 7:

@property NSArray<NSDate *>* dates;
- (NSArray<NSDate *> *)datesBeforeDate:(NSDate *)date;
- (void)addDatesParsedFromTimestamps:(NSArray<NSString *> *)timestamps;

see here:
https://developer.apple.com/library/prerelease/mac/documentation/Swift/Conceptual/BuildingCocoaApps/WorkingWithCocoaDataTypes.html#//apple_ref/doc/uid/TP40014216-CH6-ID61

吝吻 2024-07-26 17:45:39

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

- (id)objectAtIndex:(NSUInteger)index

必须将

@interface NSStringArray : NSArray

重新定义为

- (NSString *)objectAtIndex:(NSUInteger)index

NSArray

仅包含 NSString。 创建的子类可以用作直接替换,并带来许多有用的功能:编译器警告、属性访问、更好的代码创建和 Xcode 中的完成。 所有这些都是编译时功能,无需重新定义实际实现 - NSArray 的方法仍然可以使用。

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

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

示例:List 可以通过名为 NumberArray 的自定义类来实现,该类是使用以下语句创建的:

WMGENERICARRAY_INTERFACE(NSNumber *, // type of the value class
                         // generated class names
                         NumberArray, MutableNumberArray)

创建 NumberArray 后code>,您可以在项目中的任何地方使用它。 它缺少 的语法,但您可以选择自己的命名方案将它们标记为类和模板。

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

- (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.

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.

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.

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, NSDictionary and NSSet, as well as their mutable counterparts.

An example: List<int> could be realized by a custom class called NumberArray, which is created with the following statement:

WMGENERICARRAY_INTERFACE(NSNumber *, // type of the value class
                         // generated class names
                         NumberArray, MutableNumberArray)

Once you've created NumberArray, you can use it everywhere in your project. It lacks the syntax of <int>, but you can choose your own naming scheme to label these as classes as templates.

花落人断肠 2024-07-26 17:45:39

看一下:

https://github.com/tomersh/Objective-C-Generics

通过重新调整协议检查机制,它似乎是一种穷人的仿制药。

Take a look at:

https://github.com/tomersh/Objective-C-Generics

It appears to be a sort of poor-man's generics, by repurposing the protocol checking mechanism.

洛阳烟雨空心柳 2024-07-26 17:45:39

现在梦想成真了——从今天起 Objective-C 中就有了泛型(感谢 WWDC)。
这不是一个笑话 - 在 Swift 的官方页面上:

新的语法功能可让您编写更具表现力的代码,同时提高整个语言的一致性。 SDK 采用了新的 Objective-C 功能,例如泛型和可空性注释,使 Swift 代码更加干净和安全。 这里只是 Swift 2.0 增强功能的一个示例。

证明这一点的图像:Objective-C generics

Now dreams come true - there are Generics in Objective-C since today (thanks, WWDC).
It's not a joke - on official page of Swift:

New syntax features let you write more expressive code while improving consistency across the language. The SDKs have employed new Objective-C features such as generics and nullability annotation to make Swift code even cleaner and safer. Here is just a sampling of Swift 2.0 enhancements.

And image that proofs this:Objective-C generics

夜巴黎 2024-07-26 17:45:39

只想跳进这里。 我在这里写了一篇关于泛型的博客文章。

我想要贡献的是泛型可以添加到任何类,而不仅仅是苹果指出的集合类。

我已经成功地添加了各种类,因为它们的工作方式与 Apple 的集合完全相同。 IE。 编译时检查、代码完成、启用强制转换等。

享受吧。

Just want to jump in here. I've written a blog post over here about Generics.

The thing I want to contribute is that Generics can be added to any class, not just the collection classes as Apple indicates.

I've successfully added then to a variety of classes as they work exactly the same as Apple's collections do. ie. compile time checking, code completion, enabling the removal of casts, etc.

Enjoy.

柒夜笙歌凉 2024-07-26 17:45:39

Apple 和 GNUStep 框架提供的 Collections 类是半通用的,因为它们假设它们是给定的对象,一些是可排序的,一些是响应某些消息的。 对于浮点型、整数型等基元,所有 C 数组结构都完好无损且可以使用,并且有特殊的包装对象供它们在通用集合类(例如 NSNumber)中使用。
此外,Collection 类可以进行子类化(或通过类别进行专门修改)以接受任何类型的对象,但您必须自己编写所有类型处理代码。
消息可以发送到任何对象,但如果不适合该对象,则应返回 null,或者应将消息转发到适当的对象。 真正的类型错误应该在编译时捕获,而不是在运行时捕获。 在运行时它们应该被处理或忽略。
最后,Objc 提供运行时反射工具来处理棘手的情况,并且可以在发送消息或放入不适当的集合之前检查对象的消息响应、特定类型和服务。
请注意,不同的库和框架采用不同的约定来确定它们的对象在发送没有代码响应的消息时的行为方式,因此 RTFM。 除了玩具程序和调试构建之外,大多数程序不应该崩溃,除非它们真的搞砸了并尝试将错误数据写入内存或磁盘,执行非法操作(例如除以零,但您也可以捕获它),或者访问限制系统资源。
Objective-C 的动态性和运行时允许事情优雅地失败,并且应该内置到您的代码中。
(提示)如果您在函数中遇到通用性问题,请尝试一些特殊性。 使用特定类型重写函数,并让运行时在运行时选择(这就是它们被称为选择器的原因!)适当的成员函数。

Example:
    -(id) sort (id) obj;  // too generic. catches all.
     // better
    -(id) sort: (EasilySortableCollection*) esc;
    -(id) sort: (HardToSortCollection*) hsc; 
    ...
    [Sorter  sort: MyEasyColl];
    [Sorter  sort: MyHardColl];

The Collections classes provided by Apple and GNUStep frameworks are semi-generic in that they assume that they are given objects, some that are sortable and some that respond to certain messages. For primitives like floats, ints, etc, all the C arrays structure is intact and can be used, and there are special wrapper objects for them for use in the general collection classes (eg NSNumber).
In addition, a Collection class may be sub-classed (or specifically modified via categories) to accept objects of any type, but you have to write all the type-handling code yourself.
Messages may be sent to any object but should return null if it is inappropriate for the object, or the message should be forwarded to an appropriate object. True type errors should be caught at compile-time, not at run-time. At run-time they should be handled or ignored.
Finally, Objc provides run-time reflection facilities to handle tricky cases and message response, specific type, and services can be checked on an object before it is sent a message or put into an inappropriate collection.
Beware that disparate libraries and frameworks adopt different conventions as to how their objects behave when sent messages they do not have code responses for, so RTFM. Other than toy programs and debugging builds, most programs should not have to crash unless they really screw up and try to write bad data to memory or disk, perform illegal operations (eg divide by zero, but you can catch that too), or access off-limits system resources.
The dynamism and run-time of Objective-C allows for things to fail gracefully and should be built in to your code.
(HINT) if yo are having trouble with genericity in your functions, try some specificity. Write the functions over with specific types and let the runtime select (thats why they are called selectors!) the appropriate member-function at run-time.

Example:
    -(id) sort (id) obj;  // too generic. catches all.
     // better
    -(id) sort: (EasilySortableCollection*) esc;
    -(id) sort: (HardToSortCollection*) hsc; 
    ...
    [Sorter  sort: MyEasyColl];
    [Sorter  sort: MyHardColl];
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文