Accessing View in awakeFromNib?

前端 未结 5 602
醉话见心
醉话见心 2020-12-08 08:48

I have been trying to set a UIImageView background color (see below) in awakeFromNib

[imageView setBackgroundColor:[UIColor colorWithRed:0 green:0 blue:0 alp         


        
相关标签:
5条回答
  • 2020-12-08 09:19

    I believe your call to super needs to be the first line in the awakeFromNib method, otherwise the elements won't be setup yet.

    -(void)awakeFromNib {
      [super awakeFromNib];
      [imageView setBackgroundColor:[UIColor colorWithRed:0 green:0 blue:0 alpha:1.0]];
      [testLabel setText:@"Pants ..."];  
    }
    
    0 讨论(0)
  • 2020-12-08 09:20

    In case you're using a UIView subclass instead of a UIViewController subclass, you can override loadView method:

    - (void)loadView
    {
        [super loadView];
        //IBOutlets are not nil here.
    }
    
    0 讨论(0)
  • 2020-12-08 09:26

    I know, this post is a bit older, but I recently had a similar problem and would like to share its solution with you.

    Having subclassed NSTextView, I wanted to display the row colors in alternating orders. To be able to alter the colors from outside, I added two instance vars to my subclass, XNSStripedTableView:

    @interface XNSStripedTableView : NSTableView {
    
        NSColor *pColor; // primary color
        NSColor *sColor; // secondary color
    }
    
    @property (nonatomic, assign) NSColor *pColor;
    @property (nonatomic, assign) NSColor *sColor;
    
    @end
    

    Overwriting highlightSelectionInClipRect: does the trick to set the correct color for the respective 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];
    

    }

    The only problem now is, where to set the initial values for pColor and sColor? I tried awakeFromNib:, but this would cause the debugger to come up with an error. So I dug into the problem with NSLog: and found an easy but viable solution: setting the initial values in viewWillDraw:. As the objects are not created calling the method the first time, I had to check for 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];
    

    }

    I do think this solution is quite nice :-) although one could reselect the names of pColor and sColor could be adjusted to be more "human readable".

    0 讨论(0)
  • 2020-12-08 09:34

    One more answer :-) It looks like you’re getting this behaviour because the controller loads the views lazily. The view is not loaded immediately, it gets loaded the first time somebody calls the view accessor. Therefore at the time you recieve awakeFromNib the NIB loading process is done, but not for the objects inside your views. See this code:

    @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);
    }
    

    This logs:

    #1: 0
    #2: 0
    #3: 1
    

    But if you force-load the view:

    - (void) awakeFromNib
    {
        [super awakeFromNib];
        [self view]; // forces view load
        NSLog(@"#1: %i", !!foo);
    }
    

    The log changes into this:

    #3: 1
    #1: 1
    
    0 讨论(0)
  • 2020-12-08 09:40

    Are you sure the objects are not nil? NSAssert or NSParameterAssert are your friends:

    -(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];
    }
    

    If the objects are really initialized, try to log their address and make sure that the instances that appear in viewDidLoad are the same as those in awakeFromNib:

    - (void) awakeFromNib {
        NSLog(@"test label #1: %@", testLabel);
    }
    
    - (void) viewDidLoad {
        NSLog(@"test label #2: %@", testLabel);
    }
    

    If the numbers are the same, you can create a category to set a breakpoint on setBackgroundColor and peek in the stack trace to see what’s going on:

    @implementation UIImageView (Patch)
    - (void) setBackgroundColor: (UIColor*) whatever {
        NSLog(@"Set a breakpoint here.");
    }
    @end
    

    You can do the same trick using a custom subclass:

    @interface PeekingView : UIImageView {}
    @end
    
    @implementation PeekingView
    - (void) setBackgroundColor: (UIColor*) whatever {
        NSLog(@"Set a breakpoint here.");
        [super setBackgroundColor:whatever];
    }
    @end
    

    Now you’ll set your UIViewObject to be of class PeekingView in the Interface Builder and you’ll know when anybody tries to set the background. This should catch the case where somebody overwrites the background changes after you initialize the view in awakeFromNib.

    But I presume that the problem will be much more simple, ie. imageView is most probably nil.

    0 讨论(0)
提交回复
热议问题