Objective-C中NSView子类实例未初始化报错问题求解
Objective-C版NSLayoutAnchor使用时数组插入nil崩溃排查
问题背景
尝试将简单Swift应用转换为Objective-C版本,以此学习NSLayoutAnchor在Objective-C中的使用方式。原Swift应用逻辑如下:
- 创建NSView子类,通过NSColor分类生成随机颜色,设置为子类视图layer的背景色
- 在AppDelegate的
application:didFinishLaunchingWithOptions方法中创建两个该子类的实例 - 生成约束数组,将两个视图添加到父视图后激活约束即可正常运行
异常表现
转换后的Objective-C版本中,两个自定义NSView子类实例值始终为nil,单步调试可确认实例未完成初始化,应用启动时控制台输出如下崩溃信息:
-[__NSPlaceholderArray initWithObjects:count:]: attempt to insert nil object from objects[0]
初步判断为NSView子类初始化方式存在问题,经多轮排查未定位错误点。
相关代码
ColorView.m实现(RandomColor.h为实现randomColor方法的分类头文件)
#import "ColorView.h" #import "RandomColor.h" @implementation ColorView - (id)initWithFrame:(NSRect)frameRect { self = [super initWithFrame:frameRect]; if (self) { self.wantsLayer = YES; self.layer = [[CALayer alloc] init]; self.layer.backgroundColor = [[[NSColor alloc] randomColor] CGColor]; } NSLog(@"Color View Initialized"); return self; } @end
NSColor分类实现(经单独测试该部分逻辑无异常)
@implementation NSColor (RandomColor) - (NSColor *)randomColor { CGFloat r = drand48(); CGFloat g = drand48(); CGFloat b = drand48(); CGFloat alpha = 1.0; return [NSColor colorWithRed:r green:g blue:b alpha:alpha]; } @end
AppDelegate相关代码
AppDelegate.h中声明了两个ColorView类型的属性,分别命名为leftView和rightView,AppDelegate.m实现代码如下:
@synthesize leftView; @synthesize rightView; - (void)applicationDidFinishLaunching:(NSNotification *)aNotification { leftView.translatesAutoresizingMaskIntoConstraints = NO; rightView.translatesAutoresizingMaskIntoConstraints = NO; NSView *view = [self.window contentView]; [self.window setBackgroundColor:[NSColor systemMintColor]]; if (view) { [view addSubview:leftView]; [view addSubview:rightView]; [NSLayoutConstraint activateConstraints:@[ [leftView.topAnchor constraintEqualToAnchor:[view topAnchor]], [leftView.leftAnchor constraintEqualToAnchor:[view leftAnchor]], [leftView.rightAnchor constraintEqualToAnchor:[view centerXAnchor]], [leftView.widthAnchor constraintGreaterThanOrEqualToConstant:150], [leftView.heightAnchor constraintEqualToConstant:100], [rightView.centerXAnchor constraintEqualToAnchor:[view centerXAnchor] constant:50], [rightView.centerYAnchor constraintEqualToAnchor:[view centerYAnchor]], [rightView.widthAnchor constraintEqualToConstant:100], [rightView.heightAnchor constraintEqualToConstant:100] ]]; } }
已查阅NSView子类化相关官方文档,但文档内容多数无法直接编译,未提供有效参考。
错误原因
崩溃的直接原因是**leftView和rightView两个属性从未执行初始化**:Objective-C中声明的对象属性默认值为nil,直接对nil对象调用方法、传入NSLayoutConstraint的字面量数组时,就会触发数组不能存储nil对象的崩溃。
代码中另外存在两处逻辑问题:
randomColor方法定义为实例方法,但功能上属于工具类方法,应当声明为类方法,当前调用时需要先alloc NSColor实例,属于冗余且不符合设计逻辑的写法- AppKit中NSView开启layer-backed模式(设置
wantsLayer = YES)后,系统会自动生成适配的backing layer,无需手动创建CALayer实例赋值给self.layer,手动创建赋值反而可能引发显示异常。
修复方案
1. 修正NSColor分类方法定义
将randomColor改为类方法,去掉冗余的实例初始化逻辑:
// RandomColor.h中声明改为类方法 @interface NSColor (RandomColor) + (NSColor *)randomColor; @end // RandomColor.m实现对应修改 @implementation NSColor (RandomColor) + (NSColor *)randomColor { CGFloat r = drand48(); CGFloat g = drand48(); CGFloat b = drand48(); return [NSColor colorWithRed:r green:g blue:b alpha:1.0]; } @end
2. 修正ColorView初始化逻辑
删除手动创建CALayer的代码,直接调用类方法获取随机色:
@implementation ColorView - (instancetype)initWithFrame:(NSRect)frameRect { self = [super initWithFrame:frameRect]; if (self) { self.wantsLayer = YES; self.layer.backgroundColor = [[NSColor randomColor] CGColor]; } NSLog(@"Color View Initialized"); return self; } @end
3. 在AppDelegate中初始化两个视图实例
在操作视图属性、添加约束前,先完成两个ColorView实例的初始化:
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification { // 初始化两个自定义视图,初始frame传NSZeroRect即可,后续会被自动布局约束覆盖 self.leftView = [[ColorView alloc] initWithFrame:NSZeroRect]; self.rightView = [[ColorView alloc] initWithFrame:NSZeroRect]; leftView.translatesAutoresizingMaskIntoConstraints = NO; rightView.translatesAutoresizingMaskIntoConstraints = NO; NSView *contentView = [self.window contentView]; [self.window setBackgroundColor:[NSColor systemMintColor]]; if (contentView) { [contentView addSubview:leftView]; [contentView addSubview:rightView]; [NSLayoutConstraint activateConstraints:@[ [leftView.topAnchor constraintEqualToAnchor:contentView.topAnchor], [leftView.leftAnchor constraintEqualToAnchor:contentView.leftAnchor], [leftView.rightAnchor constraintEqualToAnchor:contentView.centerXAnchor], [leftView.widthAnchor constraintGreaterThanOrEqualToConstant:150], [leftView.heightAnchor constraintEqualToConstant:100], [rightView.centerXAnchor constraintEqualToAnchor:contentView.centerXAnchor constant:50], [rightView.centerYAnchor constraintEqualToAnchor:contentView.centerYAnchor], [rightView.widthAnchor constraintEqualToConstant:100], [rightView.heightAnchor constraintEqualToConstant:100] ]]; } }
修改完成后重新运行,两个视图会按照约束规则正常显示,不会再出现nil插入数组的崩溃。
内容的提问来源于stack exchange,提问作者NotationMaster
相关产品推荐
相关产品推荐

