2009-03-14 12 views
26

Ho un UIViewController personalizzato e un UIView personalizzato. Vorrei sovrascrivere la proprietà viewcontroller.view per restituire MyCustomUIView.Come sovrascrivere la proprietà "view" in UIViewController?

In questo momento ho:

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

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

Questo compila ma ottengo un avvertimento: tipo di proprietà 'vista' non corrisponde super-classe 'UIViewController' tipo di proprietà.

Come alleviare questo avviso?

+2

Credo che si dovrebbe invece usare '@ dynamic'. Per favore leggi [questa domanda] (http://stackoverflow.com/questions/1160498/synthesize-vs-dynamic-what-are-the-differences), le risposte mi sono state molto utili :) – Ondrej

+3

C'è un articolo molto bello chiamato [Override della proprietà View di UIViewController, Fatto bene] (http://travisjeffery.com/b/2012/12/overriding-uiviewcontrollers-view-property-done-right/). – lambdas

risposta

18

La risposta breve è che non è così. Il motivo è che le proprietà sono solo metodi e se si tenta di modificare il tipo restituito, si ottiene:

  • (Vista UIView *);
  • (MyView *) visualizzazione;

Objective-C fa non consentire la covarianza del tipo di ritorno.

Quello che puoi fare è aggiungere una nuova proprietà "myView", e renderla semplicemente typecast della proprietà "view". Questo allevierà le tipizzazioni nel tuo codice. Assegna semplicemente la sottoclasse view alla proprietà view e tutto dovrebbe funzionare correttamente.

+0

+1 per dare esattamente le parti mancanti da quello che ho risposto :) –

4

La proprietà/metodo della vista di UIViewController restituirà automaticamente la vista. Credo che dovrete semplicemente di gettare il risultato MyView (o semplicemente utilizzare il tipo id):

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

Credo che il codice che hai postato sopra causerà problemi. Probabilmente non si desidera creare un membro della vista (poiché in tal caso il controller memorizzerà 2 viste e potrebbe non utilizzare quella corretta internamente) o sovrascriverà la proprietà della vista (poiché UIViewController ha una gestione speciale per questo.) (Vedere this question per ulteriori informazioni su quest'ultimo.)

4

Siamo spiacenti, ma la risposta breve è sbagliata.

L'implementazione corretta di ciò sarebbe l'aggiunta di una @property al file di intestazione con il tipo restituito. Poi invece di @synthesize si aggiunge il getter e setter manualmente e restituire un tipo di cast [Visualizza Super]

per esempio la mia classe è un PlayerViewController

PlayerViewController.h

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

PlayerViewController. m

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

l'importante è mettere la classe corretta nella vista.

Inserire un UIView in cui PlayerView dovrebbe funzionare probabilmente nel Generatore di interfacce, ma non funzionerebbe correttamente nel codice.

Attualmente sto utilizzando questa implementazione.

+0

so che questa domanda era vecchia. Ma ho trovato questo e poi è venuto con la mia risposta. Spero che questo aiuti i futuri utenti. –

+0

Pensi che la proprietà dovrebbe essere forte? Voglio dire, 'UIView' ha già una' proprietà' di vista forte che ha lo stesso valore. Il modificatore di sola lettura non è più appropriato? – lambdas

+0

+1: pensavo che fosse possibile. Grazie per averlo confermato. @ lpaul7 - No, 'readonly' non ha senso perché non è possibile impostare la proprietà' view', quindi il significato di 'readonly'. È necessario avere questa proprietà come 'strong' per sovrascrivere la proprietà' view' della superclasse (che ha una dichiarazione di proprietà 'forte'). –

23

@ lpaul7 già postato un link al blog di Travis Jeffery come commento, ma è molto più corretto di tutti gli altri risposte che ha davvero bisogno il codice per essere una risposta:

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 

Se si utilizza uno xib, invece di sovrascrivere loadView modificare il tipo di visualizzazione radice del controller di visualizzazione e aggiungere IBOutlet alla proprietà.

Vedere Overriding UIViewController's View Property, Done Right per ulteriori dettagli.

+0

Utilizzando tale approccio viene visualizzato il seguente avviso del compilatore: "tipo di proprietà 'MyScrollView *' non è compatibile con il tipo 'UIView *' ereditato da 'UIViewController'" – Koen

+0

@Koen MyScrollView è una sottoclasse di UIView? Viene visualizzato l'avviso del compilatore se si utilizza UIScrollView anziché MyScrollView? – JosephH

+0

MyScrollView è una sottoclasse di 'UIScrollView'. Ho finito per rendere lo scrollView solo un contenitore per MyCustomView dove faccio tutto il disegno. Al contrario di fare tutto il disegno di MyScrollView. – Koen

0

Se qualcuno è in Swift 2.0 +, è possibile utilizzare le estensioni di protocollo per un'implementazione riutilizzabile:

// 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 
Problemi correlati