在awakeFromNib中访问View?

时间:2010-04-27 16:31:51

标签: iphone objective-c cocoa-touch

我一直在尝试在awakeFromNib中设置UIImageView背景颜色(见下文)

[imageView setBackgroundColor:[UIColor colorWithRed:0 green:0 blue:0 alpha:1.0]];

当它不起作用时,我意识到它可能是因为视图尚未加载,我应该将颜色更改移动到viewDidLoad。

我可以确认我有这个权利吗?

加里

EDIT_002:

我刚开始一个新项目,从一个干净的开始检查这个。我像往常一样设置视图。结果是控件确实在awakeFromNib中设置为(null)。这就是我所拥有的:

CODE:

@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

我很想知道这应该是否合适,从它看起来应该是的文档,但是考虑到我通常设置的方式,我不能理解为什么它在这种情况下不会。

5 个答案:

答案 0 :(得分:29)

还有一个答案:-)看起来你得到这种行为,因为控制器懒洋洋地加载视图。视图未立即加载,第一次有人调用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

答案 1 :(得分:1)

我相信你对super的调用需要成为awakeFromNib方法的第一行,否则元素将不会被设置。

-(void)awakeFromNib {
  [super awakeFromNib];
  [imageView setBackgroundColor:[UIColor colorWithRed:0 green:0 blue:0 alpha:1.0]];
  [testLabel setText:@"Pants ..."];  
}

答案 2 :(得分:0)

我知道,这篇文章有点老了,但我最近遇到了类似的问题,想与你分享它的解决方案。

有了NSTextView的子类,我希望以交替的顺序显示行颜色。为了能够改变外部的颜色,我在我的子类XNSStripedTableView中添加了两个实例变量:

@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可以调整为更“人类可读”。

答案 3 :(得分:-1)

如果您使用的是UIView子类而不是UIViewController子类,则可以覆盖loadView方法:

- (void)loadView
{
    [super loadView];
    //IBOutlets are not nil here.
}

答案 4 :(得分:-2)

您确定对象不是nil吗? NSAssertNSParameterAssert是您的朋友:

-(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

现在,您将在界面生成器中将UIViewObject设置为类PeekingView,并且您将知道何时有人尝试设置背景。这应该是在awakeFromNib初始化视图后有人覆盖背景更改的情况。

但我认为问题会更简单,即。 imageView很可能是nil