Внутри своего приложения я создал протокол под названием «Positions» и расширил класс UIView, чтобы он соответствовал этому протоколу, чтобы добавить некоторые свойства в класс UIView. Я использовал приведенный ниже код.
import Foundation
import UIKit
protocol Positions {
var initialPositions: [CGRect] {get set}
var finalPositions: [CGRect] {get set}
var positionsAreDefined: Bool {get}
}
public enum PositionsType {
case initial
}
private var initialPositionKey: UInt = 0
private var finalPositionKey: UInt = 0
extension Positions {
var initialPositions: [CGRect] {
get {
if objc_getAssociatedObject(self, &initialPositionKey) != nil {
return objc_getAssociatedObject(self, &initialPositionKey) as! [CGRect]
} else {
return [] as! [CGRect]
}
}
set {
objc_setAssociatedObject(self, &initialPositionKey, newValue, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
}
}
var finalPositions: [CGRect] {
get {
if objc_getAssociatedObject(self, &finalPositionKey) != nil {
return objc_getAssociatedObject(self, &finalPositionKey) as! [CGRect]
} else {
return [] as! [CGRect]
}
}
set {
objc_setAssociatedObject(self, &finalPositionKey, newValue, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
}
}
var positionsAreDefined: Bool {
get {return initialPositions.count != 0 && finalPositions.count != 0 && initialPositions.count == finalPositions.count}
}
var positionsCount: Int {
get {return initialPositions.count}
}
}
extension UIView: Positions {}
Итак, сегодня я попытался расширить класс UIView новым методом, который изменяет добавленные мной свойства, но компилятор выдал мне эту ошибку в строке, где я пытался изменить значение свойств:
Cannot assign to property: 'self' is immutable
Вот способ:
public func horizontallyInContainer(withShift shift: CGFloat, forExpansionNumber index: Int, forPositionType type: PositionsType) {
if self.positionsAreDefined && self.superview != nil {
if type == .initial {
var newPositions = self.initialPositions
newPositions[index].origin.x = self.superview!.bounds.width * 0.5 - self.bounds.width + shift
self.initialPositions = newPositions //Here happens the error
} else {
var newPositions = self.finalPositions
newPositions[index].origin.x = self.superview!.bounds.width * 0.5 - self.bounds.width + shift
self.finalPositions = newPositions //Also here happens
}
}
}
Может ли кто-нибудь объяснить мне природу этой ошибки?
Если вы собираетесь использовать objc_getAssociatedObject и другие функции времени выполнения Objective C, вам необходимо сделать этот протокол привязанным к классу. В противном случае это сработает, но вы заметите странное поведение. Структуры помещаются в __SwiftValue, который может использоваться средой выполнения ObjC, но у них нестабильная идентификация объекта. Идентичность объекта - это то, что среда выполнения ObjC использует в качестве ключей в своей таблице связанных объектов.
@Carcigenicate Я отредактировал свой пост
@Alexander, вы предлагаете мне поставить ключевое слово "mutating" перед объявлением метода "HorizontallyInContainer"?
@Alexander Можете ли вы объяснить мне, как я могу сделать этот протокол привязанным к классу?
Это то, что показывает @vadian в своем ответе.
Да, я видел ... спасибо тебе тоже





Сделать протокол эталонным типом
protocol Positions: AnyObject {
Хорошо, спасибо, это работает ... Можете ли вы объяснить мне, что это делает, и, может быть, указать мне на то, что я могу прочитать об этом, просто для того, чтобы снова не упасть на ту же ошибку? :)
Это обсуждается в Swift Language Guide: протоколы, однако в самой последней версии рекомендуется соответствовать AnyObject, а не абстрагироваться от class.
Протоколы, не связанные с классом, имеют семантику значений, поэтому любые изменяющие функции должны быть объявлены с помощью модификатора
mutating, как если бы они находились внутри определения структуры.