2017-01-22 8 views
2

Допустим, выРасширение протокола, похоже, не приводит к изменению переменной в потребителе?

protocol Able: class { 
    var v:UIView? { get set } 
    var x:CGFloat { get set } 
} 

тогда, конечно, когда вы используете Способный,

enter image description here

, если вы забыли "V" или "х" ...

это ошибка. Это хорошо.

Так что это:

class ScreenThing: UIViewController, Able { 
    @IBOutlet var v: UIView? 
    var x: CGFloat = 0.0 
} 

Все хорошо. Замечательно.

Принудительно, что вы указываете «v» и «x» и действительно инициализируете их.

Но. Попробуйте это ...

var _H: UInt8 = 0 

protocol Able: class { 
} 

extension Able where Self:UIViewController { 

    var p:P { 
    get { 
     return objc_getAssociatedObject(self, &_H) as! P 
     } 
    set { 
     objc_setAssociatedObject(self, &_H, newValue, .OBJC_ASSOCIATION_RETAIN_NONATOMIC) 
     __setter() 
     } 
    } 
} 

Able сейчас имеет свойство p.

Вы можете использовать p отлично либо в функциях в Able, либо в функциях в ScreenThing. Замечательно.

Однако .....

Когда вы сделаете это .....

class ScreenThing: UIViewController, Able { 
} 

вы не получить ошибку.

Вы можете забыть инициализировать «p» (он сработает).

Действительно, вам не нужно указывать «p» в качестве переменной (как вы должны с «v» и «x»).

Почему это так?

Это похоже на огромную проблему.

Есть ли что-то другое, что я должен сделать, чтобы заставить компилятор обеспечить соблюдение «p», так же как он, естественно, обычно применяет переменные в протоколах?


Другой способ посмотреть на этот вопрос:

Учитывая именно мой код выше:

есть способ для обеспечения компилятор нужен инициализатор для «р» в потребителе класс?

Например.

Я попытался это ...

class ScreenThing: UIViewController, Able { 
    var p:P 
} 

Но это не работает.

(Как это ни странно, это компиляция - на самом деле я не знаю, что, черт возьми, это делает! Кажется, это «другое» p из p в Extension. Но в любом случае это не требует необходимости для инициализатора.)

Вкратце, снова есть что-то, что я мог бы сделать или добавить выше, что заставит компилятор принудительно заставить меня инициализировать псевдо-свойство-вещь, как это обычно бывает, когда я поместите свойство в протокол, например «x» или «v».

?

  • Возможно, мне нужно добавить в протокол обычное свойство (например, «pp») и каким-то образом сделать p связанным с этим каким-то образом? Просто мысль.

(Сноска - см this понять ": класс", необходимый в протоколе выше.)


Отвечая на мой собственный вопрос:

Мой путанице выше что есть ничего не инициализировать. var p:Pв расширении (с блоками get и set code) - это просто две функции.

Инициализировать нечего.

Так например: в моем дополнительном вопросе я спрашиваю: «Как заставить соответствующие классы инициализировать его при пробуждении?» Это бессмысленно. Во всяком случае, можно спросить: «Как заставить соответствующие классы обязательно« использовать эти функции »при пробуждении?» - что не имеет ничего общего с инициализацией.

Обратите также внимание на то, что мой конкретный пример кода в вычисленной переменной происходит (не связанно) с использованием переменной, которая не инициализируется, что приводит к путанице.

+2

Я не уверен, что вы ожидаете от компилятора - 'p' не является требованием к протоколу (и даже если это так, вы уже дали ему реализацию по умолчанию в качестве вычисленного свойства), так что вы ожидая, что компилятор обеспечит выполнение вами в «ScreenThing»? – Hamish

+1

Swift - относительно новый язык, с компилятором, полным ошибок в угловых случаях. Я бы опубликовал отчет об ошибках и посмотрел, что Apple должна сказать. – dasblinkenlight

+0

Эй @hamish - Я не так эксперт, как вы, мужчина. Но простой факт заключается в том, что - глядя на конкретный пример - вам не нужно инициализировать его вообще. Обратите внимание, что приведенный пример приведет к сбою при запуске. Я никогда не видел примера get-set idiom, в Swift, где вы можете «не инициализировать его» (!) Итак, я тщательно рассмотрю, что вы сказали, и изучите вопрос человека! – Fattie

ответ

1

В усыновителе протокола вам не нужно реализовывать p, поскольку расширение протокола предоставило реализацию. Это то, что расширение протокола -.

простой пример:

protocol P {} 
extension P { 
    func greet() {print("hello")} 
} 
class C : P {} 
C().greet() 

Заметим, что (1), который компилирует, даже если С не объявить greet и (2) она работает, даже если С не содержит реализацию greet. Это потому, что это работа над расширением протокола.

+1

Также 'p' даже не является требованием протокола * в первую очередь;) – Hamish

+1

@Hamish Я смотрю на него по-другому. Для меня необходим материал расширения протокола, но он также удовлетворяет требованиям. Это самодостаточное требование! :) В конце концов, точно так же произойдет, если «greet» _were_ указан в фактическом протоколе. Первой строкой моего кода может быть «протокол P {func greet()}», но это ничего не изменит; расширение обеспечивает реализацию. – matt

+1

Истина - это была только первая строка вашего ответа, которая вызвала комментарий (вероятно, больше из nitpick), поскольку это несколько подразумевало, что если расширение * не предоставило реализацию *, то вам придется реализовать ' p' в приемнике протокола. Хотя обратите внимание, что есть тонкости (которые, я уверен, вы, вероятно, знаете), включая требования в самом объявлении протокола. Поступая таким образом, вы включаете его в таблицу свидетельских показаний протокола соответствия, предоставляя динамическую отправку при вызове требований протокола к значению, введенному в качестве протокола. – Hamish

 Смежные вопросы

  • Нет связанных вопросов^_^