Objective C块变为零
Objective C block becomes Nil
我正在从 xib 创建一个名为 HeaderView 的自定义 UIView。我在这个 HeaderView 中有一个 UIButton,在点击按钮时,我想在 ViewController 上调用一个块,其中添加了 HeaderView。这是我的 HeaderView 的代码。
头文件代码
@interface HeaderView : UIView
- (instancetype)initWithFrame:(CGRect)frame;
@property (copy) void(^seeAllHandler)();
@end
执行文件代码
@interface HeaderView()
@property (weak, nonatomic) IBOutlet UILabel *titleLabel;
@property (weak, nonatomic) IBOutlet UIButton *seeAllButton;
@property (nonatomic, strong) UIView *contentView;
@end
@implementation HeaderView
- (instancetype)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
[self setup];
}
return self;
}
- (instancetype)initWithCoder:(NSCoder *)coder
{
self = [super initWithCoder:coder];
if (self) {
}
return self;
}
- (void)awakeFromNib
{
[self.seeAllButton setTitleColor:[UIColor redColor] forState:UIControlStateNormal];
[self.seeAllButton setTitle:@"SEE ALL") forState:UIControlStateNormal];
[self.titleLabel setText:@"My Label")];
}
#pragma mark - Private methods
- (void)setup
{
//Setup view from the xib file.
self.contentView = [[[NSBundle mainBundle] loadNibNamed:NSStringFromClass(self.class) owner:self options:nil] firstObject];
[self.contentView setFrame:self.bounds];
[self addSubview:self.contentView];
self.contentView.backgroundColor = [UIColor ccNordeaPink];
self.contentView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
self.clipsToBounds = YES;
}
- (IBAction)sellAllTapped:(UIButton *)sender {
if(self.seeAllHandler != nil){
self.seeAllHandler();
}
}
@end
这是我的 ViewController viewDidLoad 方法。
@interface ViewController () <UIScrollViewDelegate, UICollectionViewDataSource, UICollectionViewDelegate>
@property (nonatomic, strong) HeaderView *headerView;
@end
- (void)viewDidLoad
{
[super viewDidLoad];
[self setupSubviews];
[self setupConstraints];
}
- (void)setupSubviews
{
self.headerView = [[HeaderView alloc] init ];
self.headerView.translatesAutoresizingMaskIntoConstraints = NO;
self.headerView.seeAllHandler = ^{
DDLogDebug(@"See all Tapped");
};
[self.view addSubView: self.headerView];
}
问题是,当点击按钮时,分配的块为零,因此不会被调用。
所以发生的事情是您在 ViewController 的 viewDidLoad 中分配块(通过 setupSubviews 方法)。我可以看到您正在以编程方式实例化 HeaderView。因此,当您分配块时,您实际上是在向实例发送消息。
但是,您还通过在 HeaderView 的 setup
方法中调用 loadNibNamed
来膨胀另一个实例。 那个 HeaderView 没有你的块,那是UI 中显示的那个。您在 HeaderView 的 contentView
中有另一个 HeaderView。
因此,actual/on-screen HeaderView 实例的处理程序 属性 为 nil,因此当它尝试将块返回给您时,它正在使用 nil也是。
处理正在发生的事情的最佳方法是进入 HeaderView 并在 awakeFromNib
中设置一个断点,在 setup
中设置另一个断点。您会看到首先调用设置。如果你在 lldb 中 po self
你将得到当前实例的地址。接下来发生的事情是 awakeFromNib 被调用并在那里遇到断点。如果您再次执行 po self
,您会看到一个不同的地址。一个不同的例子!这就是您在 UI 中看到的那个。而且它没有设置处理程序!
如果您想保留这种加载视图层次结构的方法,那么一个简单的解决方法是在 ViewController.
中从 nib 实例化 HeaderView
因此,与其执行 self.headerView = [[HeaderView alloc] init]
,不如这样做:
self.headerView = [[[NSBundle mainBundle] loadNibNamed:@"HeaderView" owner:self options:nil] firstObject];
我正在从 xib 创建一个名为 HeaderView 的自定义 UIView。我在这个 HeaderView 中有一个 UIButton,在点击按钮时,我想在 ViewController 上调用一个块,其中添加了 HeaderView。这是我的 HeaderView 的代码。
头文件代码
@interface HeaderView : UIView
- (instancetype)initWithFrame:(CGRect)frame;
@property (copy) void(^seeAllHandler)();
@end
执行文件代码
@interface HeaderView()
@property (weak, nonatomic) IBOutlet UILabel *titleLabel;
@property (weak, nonatomic) IBOutlet UIButton *seeAllButton;
@property (nonatomic, strong) UIView *contentView;
@end
@implementation HeaderView
- (instancetype)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
[self setup];
}
return self;
}
- (instancetype)initWithCoder:(NSCoder *)coder
{
self = [super initWithCoder:coder];
if (self) {
}
return self;
}
- (void)awakeFromNib
{
[self.seeAllButton setTitleColor:[UIColor redColor] forState:UIControlStateNormal];
[self.seeAllButton setTitle:@"SEE ALL") forState:UIControlStateNormal];
[self.titleLabel setText:@"My Label")];
}
#pragma mark - Private methods
- (void)setup
{
//Setup view from the xib file.
self.contentView = [[[NSBundle mainBundle] loadNibNamed:NSStringFromClass(self.class) owner:self options:nil] firstObject];
[self.contentView setFrame:self.bounds];
[self addSubview:self.contentView];
self.contentView.backgroundColor = [UIColor ccNordeaPink];
self.contentView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
self.clipsToBounds = YES;
}
- (IBAction)sellAllTapped:(UIButton *)sender {
if(self.seeAllHandler != nil){
self.seeAllHandler();
}
}
@end
这是我的 ViewController viewDidLoad 方法。
@interface ViewController () <UIScrollViewDelegate, UICollectionViewDataSource, UICollectionViewDelegate>
@property (nonatomic, strong) HeaderView *headerView;
@end
- (void)viewDidLoad
{
[super viewDidLoad];
[self setupSubviews];
[self setupConstraints];
}
- (void)setupSubviews
{
self.headerView = [[HeaderView alloc] init ];
self.headerView.translatesAutoresizingMaskIntoConstraints = NO;
self.headerView.seeAllHandler = ^{
DDLogDebug(@"See all Tapped");
};
[self.view addSubView: self.headerView];
}
问题是,当点击按钮时,分配的块为零,因此不会被调用。
所以发生的事情是您在 ViewController 的 viewDidLoad 中分配块(通过 setupSubviews 方法)。我可以看到您正在以编程方式实例化 HeaderView。因此,当您分配块时,您实际上是在向实例发送消息。
但是,您还通过在 HeaderView 的 setup
方法中调用 loadNibNamed
来膨胀另一个实例。 那个 HeaderView 没有你的块,那是UI 中显示的那个。您在 HeaderView 的 contentView
中有另一个 HeaderView。
因此,actual/on-screen HeaderView 实例的处理程序 属性 为 nil,因此当它尝试将块返回给您时,它正在使用 nil也是。
处理正在发生的事情的最佳方法是进入 HeaderView 并在 awakeFromNib
中设置一个断点,在 setup
中设置另一个断点。您会看到首先调用设置。如果你在 lldb 中 po self
你将得到当前实例的地址。接下来发生的事情是 awakeFromNib 被调用并在那里遇到断点。如果您再次执行 po self
,您会看到一个不同的地址。一个不同的例子!这就是您在 UI 中看到的那个。而且它没有设置处理程序!
如果您想保留这种加载视图层次结构的方法,那么一个简单的解决方法是在 ViewController.
中从 nib 实例化 HeaderView因此,与其执行 self.headerView = [[HeaderView alloc] init]
,不如这样做:
self.headerView = [[[NSBundle mainBundle] loadNibNamed:@"HeaderView" owner:self options:nil] firstObject];