如果使用XIB创建自定义View,则会释放Delegate

时间:2015-12-21 13:48:34

标签: ios objective-c uiview delegates

我创建了 MyCustomView.xib / h / m:,它扩展了UIView类。然后在我的Main.storyboard中,放置UIView对象,将类更改为 MyCustomView 并链接到 MainController.h 。因此,MainController包含对MyCustomView实例的引用。 要从xib加载,在MyCustomView中我执行以下操作:

- (instancetype)initWithCoder:(NSCoder *)aDecoder
{
  self = [super initWithCoder:aDecoder];
  if (self) {
    if (self.subviews.count == 0) {
      [self commonInit];
    }
 }
 return self;
}

- (instancetype)initWithFrame:(CGRect)frame
{
   self = [super initWithFrame:frame];
   if (self) {
     [self commonInit];
   }
   return self; 
}

- (void) stretchToSuperView:(UIView*)view
{
   view.translatesAutoresizingMaskIntoConstraints = NO;
   NSDictionary *bindings = NSDictionaryOfVariableBindings(view);
   NSString *formatTemplate = @"%@:|[view]|";
   for (NSString * axis in @[@"H",@"V"]) {
     NSString * format = [NSString stringWithFormat:formatTemplate,axis];
     NSArray * constraints = [NSLayoutConstraint      constraintsWithVisualFormat:format options:0 metrics:nil views:bindings];
    [view.superview addConstraints:constraints];
 }    
}

- (void)commonInit
  {
    MyCustomView* view = nil;
    NSArray *views = [[NSBundle mainBundle] loadNibNamed:@"MyCustomView" owner:self options:nil];
   view = views.firstObject;
   [self addSubview:view];
   [self stretchToSuperView:views.firstObject];
 }

这很有效,直到我想在MyCustomView中声明委托才能通知MainController任何更改(按钮点击等)。所以,我的ManController符合MyCustomViewDelegate并实现方法。

编辑1 设置代理

//MainViewController.m file
@interface MainViewController ()

@property (strong, nonatomic) IBOutlet MyCustomView *customView;
@end

@implementation MainViewController

- (void)viewDidLoad {
   [super viewDidLoad];

   self.customView.delegate = self;
 }

这里的问题是委托变为零,我不明白原因,所以不知道错误是什么。

编辑2 我认为我有两个不同的MyCustomView实例。 我在MyCustomView中添加了新属性:

@interface MyCustomView : UIView
@property (weak, nonatomic) IBOutlet UIButton *firstItem;
@property(nonatomic, weak)id <MyCustomViewDelegate> delegate;
// this is test property  
@property(nonatomic, assign)int testProperty;

@end

当我在viewDidLoad中设置此属性然后单击第一个按钮时,我看到testProperty的值为0.因此,这可能意味着IBOutlet MyCustomView * customView出现了问题。

2 个答案:

答案 0 :(得分:0)

不幸的是,我无法做出简单的评论,因此我必须提出问题并提出建议,并回答问题。

首先,我不知道你在哪里设置委托给你的MainController,但我想在控制器的viewDidLoad()中。

第二件事。如何设置MyCustomView.xib非常重要,因为您创建了一个全新的对象MyCustomView,其属性将无法从控制器中获取。

MyCustomView* view = nil; NSArray *views = [[NSBundle mainBundle] loadNibNamed:@"MyCustomView" owner:self options:nil]; view = views.firstObject; [self addSubview:view];

在不知道xib的设置和委托的设置方法的情况下,我猜这有什么可以帮到你:

  1. 在MyCustomView.xib中,将rootView的类设置为UIView。
  2. 在MyCustomView.xib中,将文件所有者的类设置为MyCustomView
  3. 将您的子视图创建为UIView。

    UIView* view = nil; NSArray *views = [[NSBundle mainBundle] loadNibNamed:@"MyCustomView" owner:self options:nil]; view = views.firstObject; [self addSubview:view];

    1. 在控制器中设置myCustomView对象的委托。
  4. self.myCustomView.delegate = self;

    我希望它会有所帮助,如果没有,那么请用代理setter代码块和你的xib设置方法扩展你的问题。 (文件类所有者,根视图类等)

答案 1 :(得分:0)

你是对的,你有两个视图对象。您添加到故事板的那个以及您通过loadNibNamed创建的那个。

底线,loadNibNamed将为您创建视图(假设您已指定MyCustomView作为NIB中指定的视图的基类;您可以将NIB的“文件所有者”留空)。然后,您可以在MyCustomView中编写一个便捷方法来实例化基于NIB的视图:

+ (instancetype)myCustomViewWithDelegate:(id<MyCustomViewDelegate>)delegate {
    NSArray *array = [[NSBundle mainBundle] loadNibNamed:@"MyCustomView" owner:delegate options:nil];
    MyCustomView *view = array.firstObject;
    NSAssert([view isKindOfClass:[MyCustomView class]], @"Base class of NIB's top level view is not MyCustomView");
    view.delegate = delegate;

    return view;
}

然后,您必须以编程方式实例化并将其添加到视图层次结构中,而不是在故事板上指定视图,例如:

- (void)viewDidLoad {
    [super viewDidLoad];

    MyCustomView *view = [MyCustomView myCustomViewWithDelegate:self];   // since `self.myCustomView` should be `weak`, let's hold the view in local variable
    [self.view addSubview:view];
    self.myCustomView = view;                                            // then set the property after the view is safely added to view hierarchy

    NSDictionary *views = @{@"myCustomView" : self.myCustomView};
    self.myCustomView.translatesAutoresizingMaskIntoConstraints = false;
    [self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|[myCustomView]|" options:0 metrics:nil views:views]];
    [self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|[myCustomView]|" options:0 metrics:nil views:views]];

    // ...
}

显然,以编程方式添加视图时,您必须指定其frameautoresizingMask,或使用如上所示的约束。