在 awakeFromNib 中访问视图?
Posted
技术标签:
【中文标题】在 awakeFromNib 中访问视图?【英文标题】:Accessing View in awakeFromNib? 【发布时间】:2010-04-27 16:31:51 【问题描述】:我一直在尝试在 awakeFromNib 中设置 UIImageView 背景颜色(见下文)
[imageView setBackgroundColor:[UIColor colorWithRed:0 green:0 blue:0 alpha:1.0]];
当它不起作用时,我意识到可能是因为视图尚未加载,我应该将颜色更改移动到 viewDidLoad。
我可以验证一下我有这个权利吗?
加里
EDIT_002:
我刚刚开始了一个新项目,以从头开始检查这一点。我像往常一样设置视图。结果是 awakeFromNib 中的控件确实设置为 (null)。这是我所拥有的:
代码:
@interface iPhone_TEST_AwakeFromNibViewController : UIViewController
UILabel *myLabel;
UIImageView *myView;
@property(nonatomic, retain)IBOutlet UILabel *myLabel;
@property(nonatomic, retain)IBOutlet UIImageView *myView;
@end
.
@synthesize myLabel;
@synthesize myView;
-(void)awakeFromNib
NSLog(@"awakeFromNib ...");
NSLog(@"myLabel: %@", [myLabel class]);
NSLog(@"myView : %@", [myView class]);
//[myLabel setText:@"AWAKE"];
[super awakeFromNib];
-(void)viewDidLoad
NSLog(@"viewDidLoad ...");
NSLog(@"myLabel: %@", [myLabel class]);
NSLog(@"myView : %@", [myView class]);
//[myLabel setText:@"VIEW"];
[super viewDidLoad];
输出:
awakeFromNib ...
myLabel: (null)
myView : (null)
viewDidLoad ...
myLabel: UILabel
myLabel: UIImageView
我很想知道这是否应该有效,从文档中看起来应该有效,但考虑到我通常设置的方式,我不太明白为什么在这种情况下它不起作用。
【问题讨论】:
【参考方案1】:另一个答案 :-) 看起来你得到了这种行为,因为控制器延迟加载视图。视图不会立即加载,它会在有人第一次调用 view
访问器时加载。因此,当您收到awakeFromNib
时,NIB 加载过程已完成,但不是您视图中的对象。请参阅此代码:
@property(retain) IBOutlet UILabel *foo;
@synthesize foo;
- (void) awakeFromNib
NSLog(@"#1: %i", !!foo);
[super awakeFromNib];
NSLog(@"#2: %i", !!foo);
- (void) viewDidLoad
NSLog(@"#3: %i", !!foo);
此日志:
#1: 0
#2: 0
#3: 1
但是如果你强制加载视图:
- (void) awakeFromNib
[super awakeFromNib];
[self view]; // forces view load
NSLog(@"#1: %i", !!foo);
日志变成这样:
#3: 1
#1: 1
【讨论】:
谢谢 Zoul,这很有趣。我想我最好还是使用 viewDidLoad 来强制视图加载首先调用它。我也读到过,在 iPhone 上使用 awakeFromNib 可能不是一个好主意,但似乎对此看法不一。再次感谢... 如果您无权访问视图,则从 awakeFromNib 执行 performSelector:withObject:delay 调用。一种技巧,但很有效。 如果覆盖 UIView 有什么解决方案吗?它没有 viewDidLoad。可能需要执行 performSelector hack。 我尝试了同样的事情,但仍然得到nil
for outlets 与 UIview 的子类绑定。
我通过放置 5 秒的 dispatch_after 检查了网点,但它仍然显示nil
【参考方案2】:
我相信您对 super 的调用必须是 awakeFromNib 方法中的第一行,否则将无法设置元素。
-(void)awakeFromNib
[super awakeFromNib];
[imageView setBackgroundColor:[UIColor colorWithRed:0 green:0 blue:0 alpha:1.0]];
[testLabel setText:@"Pants ..."];
【讨论】:
这是一个很好的猜测,确实应该首先调用super
,但在这种情况下它没有帮助。【参考方案3】:
我知道,这篇文章有点老了,但我最近遇到了类似的问题,想和你分享它的解决方案。
有了 NSTextView 的子类,我想以交替的顺序显示行颜色。为了能够从外部更改颜色,我向我的子类 XNSStredTableView 添加了两个实例变量:
@interface XNSStripedTableView : NSTableView
NSColor *pColor; // primary color
NSColor *sColor; // secondary color
@property (nonatomic, assign) NSColor *pColor;
@property (nonatomic, assign) NSColor *sColor;
@end
覆盖 highlightSelectionInClipRect: 可以为相应的 clipRect 设置正确的颜色。
- (void)highlightSelectionInClipRect:(NSRect)clipRect
float rowHeight = [self rowHeight] + [self intercellSpacing].height;
NSRect visibleRect = [self visibleRect];
NSRect highlightRect;
highlightRect.origin = NSMakePoint(NSMinX(visibleRect), (int)(NSMinY(clipRect)/rowHeight)*rowHeight);
highlightRect.size = NSMakeSize(NSWidth(visibleRect), rowHeight - [self intercellSpacing].height);
while (NSMinY(highlightRect) < NSMaxY(clipRect))
NSRect clippedHighlightRect = NSIntersectionRect(highlightRect, clipRect);
int row = (int) ((NSMinY(highlightRect)+rowHeight/2.0)/rowHeight);
NSColor *rowColor = (0 == row % 2) ? sColor : pColor;
[rowColor set];
NSRectFill(clippedHighlightRect);
highlightRect.origin.y += rowHeight;
[super highlightSelectionInClipRect: clipRect];
现在唯一的问题是,在哪里设置 pColor 和 sColor 的初始值?我尝试了 awakeFromNib:,但这会导致调试器出现错误。所以我用 NSLog: 挖掘了这个问题,并找到了一个简单但可行的解决方案:在 viewWillDraw: 中设置初始值。由于对象不是第一次调用该方法创建的,所以我必须检查 nil。
- (void)viewWillDraw
if ( pColor == nil )
pColor = [[NSColor colorWithSRGBRed:0.33 green:0.33 blue:0 alpha:1] retain];
if ( sColor == nil )
sColor = [[NSColor colorWithSRGBRed:0.66 green:0.66 blue:0 alpha:1] retain];
我确实认为这个解决方案非常好 :-) 虽然可以重新选择 pColor 和 sColor 的名称,但可以调整为更“人类可读”。
【讨论】:
【参考方案4】:您确定对象不是nil
? NSAssert
或 NSParameterAssert
是你的朋友:
-(void) awakeFromNib
NSParameterAssert(imageView);
NSParameterAssert(testLabel);
NSLog(@"awakeFromNib ...");
[imageView setBackgroundColor:[UIColor colorWithRed:0 green:0 blue:0 alpha:1.0]];
[testLabel setText:@"Pants ..."];
[super awakeFromNib];
如果对象真的被初始化了,尝试记录它们的地址,并确保viewDidLoad
中出现的实例与awakeFromNib
中出现的实例相同:
- (void) awakeFromNib
NSLog(@"test label #1: %@", testLabel);
- (void) viewDidLoad
NSLog(@"test label #2: %@", testLabel);
如果数字相同,您可以创建一个类别以在 setBackgroundColor
上设置断点并查看堆栈跟踪以查看发生了什么:
@implementation UIImageView (Patch)
- (void) setBackgroundColor: (UIColor*) whatever
NSLog(@"Set a breakpoint here.");
@end
您可以使用自定义子类来实现相同的技巧:
@interface PeekingView : UIImageView
@end
@implementation PeekingView
- (void) setBackgroundColor: (UIColor*) whatever
NSLog(@"Set a breakpoint here.");
[super setBackgroundColor:whatever];
@end
现在您将在 Interface Builder 中将 UIViewObject
设置为 PeekingView
类,并且您会知道何时有人尝试设置背景。这应该可以捕获在您初始化 awakeFromNib
中的视图后有人覆盖背景更改的情况。
但我认为问题会简单得多,即。 imageView
很可能是 nil
。
【讨论】:
您好,Zoul,非常感谢,我会在早上第一时间查看您的建议,并让您知道我的进展情况。您可能认为它很简单,让我看一下。 嗨 Zoul,控件确实为零,(参见上面的 Edit_002)【参考方案5】:如果您使用的是 UIView 子类而不是 UIViewController 子类,则可以覆盖 loadView
方法:
- (void)loadView
[super loadView];
//IBOutlets are not nil here.
【讨论】:
以上是关于在 awakeFromNib 中访问视图?的主要内容,如果未能解决你的问题,请参考以下文章
如何在同一类的 awakeFromNib 方法中获取当前视图控制器?