How to make ObjC lightweight generic type List<T: id<NSCoding>> work in Swift?

Using Imported Lightweight Generics in Swift has this example:

@interface List<T: id<NSCopying>> : NSObject
- (List<T> *)listByAppendingItemsInList:(List<T> *)otherList;
@end


@interface ListContainer : NSObject
- (List<NSValue *> *)listOfValues;
@end


@interface ListContainer (ObjectList)
- (List *)listOfObjects;
@end

It works in Swift:

    let listContainer = ListContainer()
    let list = listContainer.listOfObjects()
    list.appendingItems(in: list)

However, if I change List<T: id<NSCopying>> to List<T: id<NSCoding>> it no longer works:

    let listContainer = ListContainer()
    let list = listContainer.listOfObjects()
    list.appendingItems(in: list) // Error: 'any NSCoding' cannot be used as a type conforming to protocol 'NSCoding' because 'NSCoding' has static requirements

I believe the key difference between NSCopying and NSCoding is that NSCoding has this initializer requirement:

- (nullable instancetype)initWithCoder:(NSCoder *)coder; // NS_DESIGNATED_INITIALIZER

I have many such lightweight generics types causing this issue when I try to use them in Swift. What’s the best solution?

1 Like

The path of least resistance / practical approach would be to use a bare id (List<T: id>) in which case you might as well use just id without generics, and treat them as NSCopying instances via typecasting. Not quite type-safe but will do the job.

You mean NSCoding. That’s my current solution but as you said it is not safe, that’s why I’m looking for a better solution.