2009-03-14 4 views
26

У меня есть пользовательский UIViewController и пользовательский UIView. Я хотел бы переопределить свойство viewcontroller.view, чтобы вернуть MyCustomUIView.Как переопределить свойство «view» в UIViewController?

Прямо сейчас у меня есть:

@interface MyViewController : UIViewController {  
    IBOutlet MyView* view; 
} 

@property (nonatomic, retain) IBOutlet MyView* view; 

компилируется, но я получаю предупреждение: тип недвижимости «вид» не соответствует супер класс «» UIViewController тип недвижимости.

Как смягчить это предупреждение?

+2

Я думаю, вы скорее должны использовать '@ dynamic'. Пожалуйста, прочитайте [этот вопрос] (http://stackoverflow.com/questions/1160498/synthesize-vs-dynamic-what-are-the-differences), ответы там были действительно полезны для меня :) – Ondrej

+3

Есть очень хорошая статья [Переопределить свойство просмотра UIViewController's, Done Right] (http://travisjeffery.com/b/2012/12/overriding-uiviewcontrollers-view-property-done-right/). – lambdas

ответ

18

Короткий ответ заключается в том, что вы этого не делаете. Причина в том, что свойства - это действительно просто методы, и если вы попытаетесь изменить тип возврата, вы получите следующее:

  • (UIView *) вид;
  • (MyView *) вид;

Цель-C не разрешить возврат типа ковариации.

Что вы можете сделать, это добавить новое свойство «myView» и сделать его простым приводом типа «вид». Это облегчит приведение типов во всем коде. Просто присвойте свой подкласс view свойству view, и все должно работать нормально.

+0

+1 за то, что вы точно указали части, отсутствующие в ответе :) –

4

Свойство/метод представления UIViewController автоматически вернет ваше представление. Я думаю, вы просто должны привести результат к MyView (или просто использовать тип документа):

MyView *myView = (MyView*)controller.view; 
id myView = controller.view; 

Я думаю, что код, который вы выложили выше причинит вам неприятности. Вы, вероятно, не хотите сами создавать элемент представления (потому что тогда контроллер будет хранить 2 представления и может не использовать правильный внутри) или переопределить свойство представления (поскольку UIViewController имеет специальную обработку для него.) (См. this question для получения дополнительной информации о последних.)

4

Извините, но ваш короткий ответ неверен.

Правильная реализация этого будет заключаться в добавлении @property в заголовочный файл с типом возвращаемого значения. Тогда вместо @synthesize вы добавляете геттер и сеттер вручную и возвращать тип произнесения из [зрения] супер

, например, мой класс является PlayerViewController

PlayerViewController.h

@property (strong, nonatomic) IBOutlet PlayerView *view; 

PlayerViewController. м

- (PlayerView *)view{ 
    return (PlayerView*)[super view]; 
} 
- (void)setView:(PlayerView *)view{ 
    [super setView:view]; 
} 

Главное, чтобы поставить правильный класс в представление.

Ввод UIView, в котором проходит PlayerView, вероятно, будет работать в построителе интерфейса, но не будет работать корректно в коде.

В настоящее время я использую эту реализацию.

+0

Я знаю, что этот вопрос был старый. Но я нашел это, а затем придумал свой собственный ответ. Надеюсь, что это поможет будущим пользователям. –

+0

Считаете ли вы, что собственность должна быть сильной? Я имею в виду, что 'UIView' уже имеет сильное свойство' view', которое имеет одинаковое значение. Не подходит ли модификатор readonly? – lambdas

+0

+1: Я думал, что это возможно. Спасибо, что подтвердили это. @ lpaul7 - Нет, 'readonly' не имеет смысла, потому что тогда вы не сможете установить свойство' view', следовательно, значение 'readonly'. Вам нужно, чтобы это свойство было «сильным», чтобы переопределить свойство «вид» суперкласса (которое имеет объявление свойства «сильный»). –

23

@ lpaul7 уже разместил ссылку на блог Travis Джефри в качестве комментария, но это гораздо более правильно, чем все другие ответы, что он действительно нужен код, чтобы быть ответом:

ViewController.h:

@interface ViewController : UIViewController 

@property (strong, nonatomic) UIScrollView *view; 

@end 

ViewController.m:

@implementation ViewController 

@dynamic view; 

- (void)loadView { 
    self.view = [[UIScrollView alloc] initWithFrame:[[UIScreen mainScreen] applicationFrame]]; 
} 

@end 

Если вы используете xib, вместо переопределения loadView измените тип корневого представления вашего контроллера представления и добавьте IBOutlet в собственность.

Для получения более подробной информации см. Overriding UIViewController's View Property, Done Right.

+0

Используя этот подход, я получаю следующее предупреждение о компиляторе: «Тип свойства« MyScrollView * »несовместим с типом« UIView * », унаследованным от« UIViewController »» – Koen

+0

@Koen Является ли ваш MyScrollView подклассом UIView? Получаете ли вы предупреждение компилятора, если вы используете UIScrollView вместо MyScrollView? – JosephH

+0

MyScrollView является подклассом 'UIScrollView'. Я закончил создание scrollView только контейнера для MyCustomView, где я делаю весь рисунок. В отличие от всего рисунка MyScrollView. – Koen

0

Если кто-то на Swift 2.0+, вы можете использовать расширение протокола для многоразовой реализации:

// Classes conforming to this protocol... 
protocol CustomViewProvider { 

    typealias ViewType 
} 

// ... Will get customView accessor for free 
extension CustomViewProvider where Self: UIViewController, Self.ViewType: UIView { 

    var customView: Self.ViewType { 
     return view as! Self.ViewType 
    } 
} 


// Example: 
extension HomeViewController: CustomViewProvider { 
    typealias ViewType = HomeView 
} 

// Now, we can do something like 
let customView: HomeView = HomeViewController().customView 
Смежные вопросы