2014-11-21 9 views
5

Ich bin hoffnungslos fest und ich würde einen Zeiger schätzen.Benutzerdefinierte UIView-Unterklasse erfordert, dass wakeFromNIB zweimal aufgerufen wird

Wir versuchen, einen View-Controller zu erstellen, der mehrere Ansichten enthält, die eine Unterklasse von UIView sind. Alles funktioniert "gut", außer dass wir die Ansicht entweder manuell initialisieren oder watchFromNib manuell erneut aufrufen müssen, was nicht erlaubt ist. Hier

ist das Problem ...

Unterklasse UIView Header-Datei:

#import <UIKit/UIKit.h> 
@interface introView : UIView 
@property (strong, nonatomic) UIView *view; 
@property (strong, nonatomic) NSString *title; 
@property (strong, nonatomic) IBOutlet UILabel *titleLabel; 
@end 

Unterklasse UIView Hauptdatei:

#import "introView.h" 

@interface introView() 
@end 

@implementation introView 

-(id)init 
{ 
    NSArray *subviewArray = [[NSBundle mainBundle] loadNibNamed:@"introView" owner:self options:nil]; 
    id mainView = [subviewArray objectAtIndex:0]; 
    return mainView; 
} 
- (void) awakeFromNib 
{ 
    [super awakeFromNib]; 
    [self initialize]; 
    [self addSubview:self.view]; 
} 

-(void)initialize 
{ 
    NSLog(@"title: %@", self.title); 
    self.titleLabel.text = self.title; 
} 

Wir haben dann die Ansicht initialisieren von einem View-Controller dies zu tun :

introView *view = [[introView alloc]init]; 
view.title = @"Test"; 
[self addSubview:view]; 

Hier ist das Problem - durch Aufrufen dieser Ansicht wird die Ansicht korrekt angezeigt, aber der Titel ist NULL;

[43605:1957090] title: (null) 

Wenn jedoch wir awakeFromNib rufen dann wieder die Ansicht richtig

In der Steuerung Ansicht initialisiert:

introView *view = [[introView alloc]init]; 
view.title = @"Test; 
[self addSubview:view]; 
[view awakeFromNib]; 

Dann funktioniert es:

2014-11-21 09:33:03.500 Test[43706:1972060] title: (null) 
2014-11-21 09:33:03.500 Test[43706:1972060] title: Test 

Alternativ, wenn ich das machen initialisiere Methode public und rufe das nach der Initialisierung auf. Aber das Niederlagen der Zweck in meinen Augen ...

Im View-Controller:

introView *view = [[introView alloc]init]; 
view.title = @"Test; 
[self addSubview:view]; 
[view initialize]; //calling the method directly... 

Es scheint mir, dass wir irgendwie in einen Zustand ausgeführt wird, wo die Aussicht ist noch nicht fertig, aber dann funktioniert es bei der zweite Versuch (obwohl der Aufruf wakeFromNib illegal ist)

Wieder sind die Ausgänge korrekt eingerichtet, der Dateibesitzer ist gesetzt ... es dauert nur zwei wakeFromNib Anrufe.

Jede Hilfe wird geschätzt.

---------------- UPDATE ------------------

Danke Jungs, ich schätze den Zeiger . Ich habe den Initialisierer wie beschrieben implementiert, aber ich habe das gleiche Problem. Außerdem habe ich das GitHub-Beispiel als ein sauberes Beispiel verwendet und versucht, dieser Ansicht eine Variable zuzuweisen, und selbst das zeigt das gleiche Verhalten. Daher fange ich an zu denken, dass ich woanders etwas falsch mache. Siehe hier:

// 
// SubClassView.h 
// CustomView 
// 
// Created by Paul Solt on 4/28/14. 
// Copyright (c) 2014 Paul Solt. All rights reserved. 
// 

#import <UIKit/UIKit.h> 
#import "PSCustomViewFromXib.h" 

@interface SubClassView : PSCustomViewFromXib 
@property (strong, nonatomic) NSString *title; 
@end 

SubclassView.m

// 
// SubClassView.m 
// CustomView 
// 
// Created by Paul Solt on 4/28/14. 
// Copyright (c) 2014 Paul Solt. All rights reserved. 
// 

#import "SubClassView.h" 

@interface SubClassView() 
@property (weak, nonatomic) IBOutlet UILabel *label; 
@property (weak, nonatomic) IBOutlet UISwitch *onSwitch; 


@end 

@implementation SubClassView 

// Note: You can customize the behavior after calling the super method 

// Called when loading programatically 
- (id)initWithFrame:(CGRect)frame { 
    self = [super initWithFrame:frame]; 
    if(self) { 
     // Call a common method to setup gesture and state of UIView 
     [self setup]; 
    } 
    return self; 
} 

// Called when loading from embedded .xib UIView 
- (id)initWithCoder:(NSCoder *)aDecoder { 
    self = [super initWithCoder:aDecoder]; 
    if(self) { 
     // Call a common method to setup gesture and state of UIView 
     [self setup]; 
    } 
    return self; 
} 

- (void)setup { 
    // Add a gesture to show that touch input works on full bounds of UIView 
    NSLog(@"%@", self.title); 
    UIPanGestureRecognizer *panGesture = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(handlePanGesture:)]; 
    [self addGestureRecognizer:panGesture]; 
} 

- (void)handlePanGesture:(UIPanGestureRecognizer *)gesture { 
    NSLog(@"Pan: %@", NSStringFromCGPoint([gesture locationInView:gesture.view])); 
} 
- (IBAction)switchChanged:(UISwitch *)sender { 
    NSLog(@"Switch: %d", sender.on); 
} 

@end 

-View-Controller-Klasse

// 
// ViewController.m 
// CustomView 
// 
// Created by Paul Solt on 4/28/14. 
// Copyright (c) 2014 Paul Solt. All rights reserved. 
// 

#import "ViewController.h" 
#import "SubClassView.h" 
#import "LabelMadness.h" 

@interface ViewController() 

@end 

@implementation ViewController 

- (void)viewDidLoad 
{ 
    [super viewDidLoad]; 


    // Add a custom view's programmatically (position using 1/2 width and height) 

    SubClassView *oneView = [[SubClassView alloc] init]; 
    oneView.center = CGPointMake(80 + 80, 282 + 40); 
    oneView.backgroundColor = [UIColor blueColor]; 
    oneView.title = @"Test2"; 
    [self.view addSubview:oneView]; 

} 

@end 

------- OUTPUT -----

2014-11-21 11:49:38.893 CustomView[45653:2123668] LabelMadness.initWithFrame: 
2014-11-21 11:49:38.893 CustomView[45653:2123668] (null) 

Was mache ich hier falsch?

+0

Sie Code ist etwas verwirrend. Was ist in der introView-Klasse self.view (in [self addSubview: self.view])? Wie sieht mainView aus (welche Teilansichten hat es)? – rdelmar

Antwort

2

Sie brauchen nicht watchFromNib überhaupt zu verwenden. Wenn Sie introView wollen ihre eigene Feder laden, können Sie das tun, wie so (die Klasse der Ansicht introView in der xib Datei ändern),

-(instancetype)init{ 
    if (self = [super init]) { 
     NSArray *subviewArray = [[NSBundle mainBundle] loadNibNamed:@"introView" owner:self options:nil]; 
     self = [subviewArray objectAtIndex:0]; 
    } 
    return self; 
} 

den Titel zu setzen, können Sie die Setter Ihrer außer Kraft setzen title property,

-(void)setTitle:(NSString *)title { 
    _title = title; 
    self.titleLabel.text = title; 
} 

Der Code in Ihrem Controller wäre derselbe wie der, den Sie ursprünglich ausprobiert haben.

+0

Ich habe das versucht, aber dann bekomme ich eine Ausnahme ... *** Beenden App aufgrund der nicht abgefangenen Ausnahme 'NSInvalidArgumentException', Grund: '- [UIView setTitle:]: unerkannter Selektor gesendet Instanz 0x7fbc4d8c4040' – user3757285

+0

@ user3757285, Es klingt wie Sie haben die Klasse der Sicht in Ihrer XIB nicht in Ihre benutzerdefinierte Klasse geändert (deshalb sagt der Fehler UIView nicht introView). – rdelmar

+0

Sie sind richtig und es war falsch, aber es ändert nichts. Ich bekomme eine Ausnahme. Ich fange jedoch an zu denken, dass meine ganze Herangehensweise etwas fehlerhaft ist. Ist es nicht möglich, eine globale Variable als Teil der init-Funktion zuzuordnen? Muss ich [view initialize] aufrufen, damit die Variable abgeholt wird? Es macht keinen Sinn für mich, aber so funktioniert es ... – user3757285

0

Also, haben Sie die Ansicht in einer .xib oder in Storyboard?

Es sieht aus wie aus einem .xib, so dass Sie bei this answer

aussehen sollten Sie sollten nicht die init-Methode überschreiben, und Sie sollten nicht init es im Code Alloc. Wenn Sie dies tun, werden die Ansichten, die Sie im Interface Builder erstellt haben, nicht geladen.

Also statt Alloc init, folgen Sie der Antwort, die ich darauf hingewiesen habe und etwas ähnliches tun.

Wie dem auch sei, ich kann nicht sehen, wo initialisieren Sie Ihre

@property (strong, nonatomic) UIView *view; 

Ist das nicht ein IBOutlet und Sie es nie irgendwo init, so offensichtlich wird, dass immer nil

Verwandte Themen