【问题标题】:Accessing View in awakeFromNib?在 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

我很想知道这是否应该有效,从文档中看起来应该有效,但考虑到我通常设置的方式,我不太明白为什么在这种情况下它不起作用。

【问题讨论】:

    标签: iphone objective-c cocoa-touch


    【解决方案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】:

      您确定对象不是nilNSAssertNSParameterAssert 是你的朋友:

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

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多