Вы можете вызвать [self.view setNeedsDisplay]
, но не self.view.i
, потому что свойство view
UIViewController
имеет тип UIView
.
self.myView был назначен self.view уже в viewDidLoad
Помните, что фактическое назначение происходит во время выполнения, а ошибки компилятора генерируются во время компиляции. Компилятор понятия не имеет, в каком порядке могут вызываться методы вашего контроллера представления, поэтому он не может делать никаких предположений о фактическом типе значения свойства, кроме исходного объявления свойства. Что касается Xcode, self.view
— это просто UIView
.
Как было предложено выше, вы можете переопределить объявление свойства, чтобы сообщить компилятору, что ваше представление имеет тип MyView
. Хотя ваш подход с использованием свойства self.myView
в любом случае может быть предпочтительнее: он позволяет вам изменить иерархию представлений в будущем, не меняя ваш интерфейс, и не испортит унаследованные методы. UITableViewController
делает то же самое: оба свойства view
и tableView
возвращают один и тот же экземпляр представления, но свойства имеют разные типы.
Важно помнить, что тип свойства не обязательно совпадает с типом его значения. self.view
могло быть назначено экземпляру MyView
, но свойство по-прежнему относится к типу UIView
. Независимо от типа назначенного ему объекта, метод доступа к свойству по-прежнему является методом с типом возвращаемого значения UIView
.
Итак, с точки зрения компилятора, self.view
— не что иное, как простое старое UIView
, даже если вы знаете, что это не так.
Я думаю, это помогло бы подробнее рассказать о том, что такое свойства, и провести различие между свойством и экземпляром. При создании такого свойства:
@interface MyViewController : UIViewController
@property(strong, nonatomic) MyView *myView;
@end
Компилятор преобразует его в переменную, метод доступа («геттер») и метод мутатора («сеттер»). Свойство является просто сокращением для объявления таких методов:
@interface MyViewController : UIViewController
{
MyView *_myView;
}
- (MyView *)myView; // accessor / getter
- (void)setMyView:(MyView *)myView; // mutator / setter
@end
@implementation MyViewController
- (MyView *)myView
{
return _myView;
}
- (void)setMyView:(MyView *)myView
{
_myView = myView;
}
@end
Когда вы вызываете self.myView
или self.view
, вы фактически вызываете метод доступа; это эквивалентно [self myView]
или [self view]
. Он возвращает указатель на объект в памяти. Поскольку вы присвоили self.view = self.myView
, оба свойства устанавливаются для одного и того же объекта; таким образом, и self.view
, и self.myView
возвращают указатель на один и тот же объект.
Обобщить:
- Присвоение
self.view = self.myView
не вызывает ошибки компиляции, поскольку MyView
является подклассом UIView
. Обратите внимание, что присвоение self.myView = self.view
будет генерировать предупреждение, поскольку UIView
не является подклассом MyView
.
- Вызов
[self.view setNeedsDisplay]
приводит к тому, что myView
рисует себя, потому что один и тот же экземпляр назначается обоим свойствам. Если вы зарегистрируете описания (NSLog(@"view=%@, myView=%@", self.view, self.myView)
) для обоих свойств, вы увидите, что они имеют одинаковый адрес памяти.
- Вы не можете вызвать
self.view.i
, потому что свойство view
объявлено как имеющее тип UIView
, а UIView
не имеет метода с именем i
.
person
Austin
schedule
30.01.2014