Этот вопрос спрашивает, можно ли использовать подписку с CKRecord
в Swift. Хотя я уже знал, как сделать то, что хотел вопрошавший, каждая его перестановка приводит к переполнению стека:
subscript(key: String) -> CKRecordValue? {
get {
return objectForKey(key) as CKRecordValue?
}
set {
setObject(newValue, forKey: key)
}
}
Переполнение стека происходит в геттере. (Я никогда не пробовал сеттер, так что это может произойти и там.) Я пытался реализовать с помощью objectForKey:
, objectForKeyedSubscript:
и valueForKey:
. Все дают один и тот же результат: переполнение стека.
Это очень странно, так как CKRecord
наверняка написан на Objective-C. Зачем ему рекурсивно вызывать метод Swift subscript
? Это не имеет никакого смысла. Нейт Кук в своем ответе на вопрос задается вопросом, почему Свифт не соединяет objectForKeyedSubscript:
автоматически. Что ж, возможно, код для этого не полностью запечен, но вызывает эту проблему. Мне придется попробовать это с другим классом, у которого есть objectForKeyedSubscript:
.
ОБНОВИТЬ
Похоже, что objectForKeyedSubscript:
обычно подключается мостом. Я создал класс в Objective-C с соответствующими методами, добавил его в заголовок моста, и индексаторы были там и скомпилированы без проблем. Более того, он работал без переполнения стека.
Это означает, что с CKRecord
происходит что-то очень необычное.
ТЕОРИЯ
Если вы создаете класс в Swift, который происходит от NSObject
и реализует в нем метод subscript
с ключом String
, он становится objectForKeyedSubscript:
. (Я подозреваю, что для «чистых классов Swift» это не так.) Вы можете проверить это, импортировав свой класс Swift в Objective-C и убедившись, что objectForKeyedSubscript:
там есть.
Поскольку CKRecord
происходит от NSObject
, реализация subscript
переопределяет реализацию по умолчанию. Кроме того, кажется, что все objectForKey:
и valueForKey:
в конечном итоге вызывают objectForKeyedSubscript:
, что приводит к (читай: «то же самое, что и») вызову subscript
, что вызывает переполнение стека.
Это может объяснить, почему происходит переполнение стека. Это по-прежнему не объясняет, почему objectForKeyedSubscript:
не было автоматически соединено мостом, но, возможно, это связано с тем, что определение setObject:forKeyedSubscript:
имеет сигнатуру типа, немного отличающуюся от канонической: - (void)setObject:(id <CKRecordValue>)object forKeyedSubscript:(NSString *)key;
. Это не имеет значения для Objective-C, но может привести к срабатыванию «кода моста». В конце концов, Swift довольно новый.