2009-03-14 6 views
26

Ich habe einen benutzerdefinierten UIViewController und benutzerdefinierte UIView. Ich möchte die ViewController.view -Eigenschaft überschreiben, um MyCustomUIView zurückzugeben.Wie überschreibe ich die "Ansicht" -Eigenschaft in UIViewController?

Im Moment habe ich:

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

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

Dies kompiliert, aber ich erhalte eine Warnung: Eigenschaft ‚view‘ Typ nicht Superklasse Objekttyp ‚UIViewController‘ entspricht.

Wie löse ich diese Warnung?

+2

Ich glaube, Sie lieber '@ dynamic' verwenden sollten. Bitte lesen [diese Frage] (http://stackoverflow.com/questions/1160498/synthesize-vs-dynamic-what-are-the-differences), die Antworten dort waren wirklich hilfreich für mich :) – Ondrej

+3

Es gibt sehr schönen Artikel [Overriding UIViewControllers View Property, Done Right] aufgerufen (http://travisjeffery.com/b/2012/12/overriding-uiviewcontrollers-view-property-done-right/). – lambdas

Antwort

18

Die kurze Antwort ist, dass Sie nicht. Der Grund ist, dass Eigenschaften wirklich nur Methoden sind, und wenn Sie versuchen, den Rückgabetyp zu ändern, erhalten Sie Folgendes:

  • (UIView *) anzeigen;
  • (MyView *) Ansicht;
  • Objective-C tut nicht erlauben Rückgabetyp Kovarianz.

    Sie können eine neue Eigenschaft "myView" hinzufügen und die Eigenschaft "view" einfach typisieren. Dadurch werden Typumwandlungen im gesamten Code verringert. Ordnen Sie Ihre View-Unterklasse einfach der View-Eigenschaft zu, und alles sollte gut funktionieren.

    +0

    +1 für genau die fehlenden Teile von dem, was ich antwortete :) –

    4

    Die View-Eigenschaft/Methode des UIViewControllers gibt Ihre Ansicht automatisch zurück. Ich glaube, Sie müssen nur das Ergebnis MyView werfen (oder nur die ID-Typ verwenden):

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

    ich glaube, der Code, den Sie oben geschrieben haben, werden Sie Probleme verursachen. Wahrscheinlich möchten Sie nicht selbst ein View-Element erstellen (weil der Controller dann 2 Views speichert und möglicherweise nicht das richtige intern verwendet) oder die View-Eigenschaft überschreiben (weil UIViewController eine spezielle Behandlung dafür hat.) (Siehe this question Für weitere Informationen über Letzteres.)

    4

    Entschuldigung, aber Ihre kurze Antwort ist falsch.

    Die korrekte Implementierung davon wäre, eine @property der Header-Datei mit Ihrem Rückgabetyp hinzuzufügen. Dann statt @synthesize Sie die Getter und Setter manuell hinzufügen und einen gegossenen Typ aus [super Ansicht]

    zum Beispiel meine Klasse zurückgeben ein PlayerViewController

    PlayerViewController.h

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

    PlayerViewController. m

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

    die wichtige Sache ist, die korrekte Klasse in die Ansicht zu setzen.

    Das Angeben einer UIView, wo ein PlayerView ausgeführt wird, würde wahrscheinlich im Interface Builder funktionieren, würde aber im Code nicht korrekt funktionieren.

    Ich verwende derzeit diese Implementierung.

    +0

    Ich weiß, dass diese Frage alt war. Aber ich fand das und kam dann auf meine eigene Antwort. Ich hoffe, dies hilft den zukünftigen Benutzern. –

    +0

    Glauben Sie, dass die Immobilie stark sein sollte? Ich meine, 'UIView' haben bereits eine starke Eigenschaft' view', die den gleichen Wert hat. Ist Readonlyly Modifier nicht besser geeignet? – lambdas

    +0

    +1: Ich dachte, das war möglich. Danke für die Bestätigung. @ lpaul7 - Nein, 'readonly' macht keinen Sinn, weil dann die' view'-Eigenschaft nicht gesetzt werden kann - daher die Bedeutung von 'readonly'. Sie müssen diese Eigenschaft als 'strong' haben, um die Eigenschaft' view' der Superklasse (die eine Eigenschaftsdeklaration von 'strong' hat) zu überschreiben. –

    23

    @ lpaul7 posted bereits einen Link zu Travis Jeffery Blog als Kommentar, aber es ist so viel mehr richtig als alle anderen Antworten, dass es wirklich den Code muss eine Antwort auf sein:

    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 
    

    Wenn Sie eine xib verwenden, ändern Sie anstelle des Typs loadView den Typ der Stammansicht des View-Controllers und fügen Sie der Eigenschaft IBOutlet hinzu.

    Weitere Informationen finden Sie unter Overriding UIViewController's View Property, Done Right.

    +0

    Mit diesem Ansatz bekomme ich die folgende Compiler-Warnung: "Eigenschaftstyp 'MyScrollView *' ist nicht kompatibel mit Typ 'UIView *' geerbt von 'UIViewController'" – Koen

    +0

    @Koen Ist Ihre MyScrollView eine Unterklasse von UIView? Erhalten Sie die Compiler-Warnung, wenn Sie UIScrollView anstelle von MyScrollView verwenden? – JosephH

    +0

    MyScrollView ist eine Unterklasse von 'UIScrollView'. Ich habe das ScrollView nur zu einem Container für MyCustomView gemacht, wo ich die ganze Zeichnung mache. Im Gegensatz zum Zeichnen der MyScrollView. – Koen

    0

    Wenn jemand auf Swift 2.0+ ist, können Sie Protokollerweiterungen für eine wiederverwendbare Implementierung verwenden:

    // 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 
    
    Verwandte Themen