IT story

Objective-C에 강력한 형식의 컬렉션이 있습니까?

hot-time 2020. 6. 22. 07:40
반응형

Objective-C에 강력한 형식의 컬렉션이 있습니까?


저는 Mac / iPhone 프로그래밍과 Objective-C를 처음 사용합니다. C #과 Java에는 "generics"가 있으며,이 클래스의 멤버는 선언 된 유형 만 가능합니다. 예를 들어 C #에서

Dictionary<int, MyCustomObject>

정수 키와 MyCustomObject 유형의 값만 포함 할 수 있습니다. Objective-C에도 비슷한 메커니즘이 있습니까?


Xcode 7에서 Apple은 Objective-C에 'Lightweight Generics'를 도입했습니다. 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는 일반 정보를 완전히 무시합니다. 더 이상 Swift 3 이상에서는 적용되지 않습니다.

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

이러한 Foundation 컬렉션 클래스 외에도 Objective-C 경량 제네릭은 Swift에서 무시됩니다. 경량 제네릭을 사용하는 다른 유형은 매개 변수가없는 것처럼 Swift로 가져옵니다.

Objective-C API와 상호 작용


이 답변은 구식이지만 역사적 가치가 있습니다. Xcode 7부터 6 월 '15의 Connor의 답변이 더 정확합니다.


아니요, Objective-C에는 고유 한 사용자 지정 컬렉션 클래스에서 C ++ 템플릿을 사용하지 않는 한 제네릭이 없습니다 (강력하지 않습니다).

Objective-C에는 기능으로 동적 입력이 있습니다. 즉, 모든 객체가 메시지를 수신 할 수 있으므로 런타임은 객체 유형에 신경 쓰지 않습니다. 내장 컬렉션에 객체를 추가하면 마치 마치 마치 마치 객체처럼 취급됩니다 id. 그러나 걱정하지 마십시오. 보통과 같은 객체에 메시지를 보내십시오. 컬렉션의 하나 이상의 객체가 보내는 메시지에 응답하지 않는 한 제대로 작동합니다 .

제네릭은 강력한 정적 형식 언어이므로 Java 및 C #과 같은 언어에서 필요합니다. Objective-C의 다이나믹 한 타이핑 기능과는 완전히 다른 볼 게임입니다.


아니요, 그러나 저장하려는 객체 유형으로 주석을 달 수 있음을 분명히하기 위해 요즘 Java 1.4로 무언가를 작성해야 할 때이 작업을 몇 번 수행했습니다. 예 :

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

또는

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

Objective-C에는 제네릭이 없습니다.

문서에서

배열은 정렬 된 객체 모음입니다. Cocoa는 NSArray, NSMutableArray (NSArray의 서브 클래스) 및 NSPointerArray와 같은 여러 배열 클래스를 제공합니다.


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


이것은 Xcode 7에서 출시되었습니다 (최종!)

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.


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.


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.


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


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.


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];

참고URL : https://stackoverflow.com/questions/848641/are-there-strongly-typed-collections-in-objective-c

반응형