Are there strongly-typed collections in Objective-

2019-01-03 23:34发布

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?

11条回答
干净又极端
2楼-- · 2019-01-04 00:14

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.

查看更多
时光不老,我们不散
3楼-- · 2019-01-04 00:18

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

查看更多
看我几分像从前
4楼-- · 2019-01-04 00:19

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

查看更多
手持菜刀,她持情操
5楼-- · 2019-01-04 00:19

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 = ...
查看更多
孤傲高冷的网名
6楼-- · 2019-01-04 00:23

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];
查看更多
\"骚年 ilove
7楼-- · 2019-01-04 00:27

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.

查看更多
登录 后发表回答