Поле класса Swift типа var Array преобразуется в неизменяемый NSArray вместо NSMutableArray

Простой класс Swift имеет поле типа var Array. Когда класс адаптирован к Objective-C, тип поля отображается как NSArray (неизменный), в то время как он должен быть NSMutableArray (изменчивым)

class Categoryy: NSObject {

    var items = Array<Item>()

}

Класс Quicky Categoryy адаптирован к Objective-C в сгенерированном Xcode заголовке файла MODULE_NAME-swift.h следующим образом:

SWIFT_CLASS("_TtC8waiterio9Categoryy")
@interface Categoryy : NSObject
@property (nonatomic, copy) NSArray * items;
- (instancetype)init OBJC_DESIGNATED_INITIALIZER;
@end

Есть ли способ для элементов var: Поле массива, которое должно быть преобразовано в изменяемый NSMutableArray в Objective-c?

Ответ 1

Это потому, что свойство items на самом деле неизменный.

Как вы знаете, из-за характера struct на основе реализации Array в Swift, следующий код не влияет на cat.items.

let cat = Categoryy()

var _items = cat.items
_items.append(item)

Вместо этого вам нужно позвонить так:

cat.items.append(item)

С другой стороны, в Objective-C, [cat.items addObject:item] точно такая же, как и следующая:

id _items = [cat items];
[_items addObject:item];

Это очень похоже на нерабочий код Swift.

Скажем, Objective-C не имеет эквивалентного свойства/метода, вызывающего семантику как cat.items.append(item) в Swift.

Это похоже на:

// Objective-C
CGRect frame = view.frame;
view.frame = CGRectMake(frame.origin.x, 50, frame.size.width, frame.size.height)

// Swift
view.frame.origin.y = 50

-

Возможно, Apple может реализовать это как NSMutableArray (или частный подкласс), конечно, вы можете запросить это. Я сомневаюсь, что Apple это сделает, потому что это разрывает безопасность типа времени компиляции Generics.

В любом случае, я думаю, вы должны реализовать Categoryy следующим образом:

class Categoryy: NSObject {
    var items:[Item] = []

    func addItem(item:Item) {
        items.append(item)
    }

    func setItem(item:Item, atIndex:Int) {
        items[atIndex] = item;
    }

    // and so on ..
}

Ответ 2

Если вы хотите NSMutableArray, самый простой способ - просто использовать NSMutableArray в Swift. Array<T> не может (и не может) одновременно вести себя как (неизменяемый) NSArray и NSMutableArray в одно и то же время - прямо сейчас, то, что он ведет, является как неизменным NSArray. Swift может использовать встроенный тип класса, который соответствует NSMutableArray тем, что Array<T> соответствует NSArray.

Другой альтернативой является использование класса Swift для обтекания NSMutableArray с @objc открытых методов для доступа к NSMutableArray. Это также позволяет использовать generics для ограничения элементов до T.

Ответ 3

В качестве обходного пути вы можете вызвать append в файле Swift с помощью метода вместо доступа к массиву Swift непосредственно в Objective-C.

Swift:

func addItem(item:Item)
{
    items.append(item)
}

Objective-C:

[yourSwiftObject addItem:item];