Screen refresh?

Discussion in 'iOS Programming' started by xArtx, Apr 21, 2012.

  1. xArtx macrumors 6502a

    Joined:
    Mar 30, 2012
    #1
    Hi Guys,
    I'm playing with some Quartz 2D samples,
    and have gotten everything to work as expected with regard to drawing primitives, etc.

    I am now trying to move some text on the screen

    Code:
        CGContextSetTextDrawingMode(context, kCGTextFill);
        CGContextShowTextAtPoint(context, 88.0, y, kTextString, kTextStringLength);
        
    
    // increment or decrement y coord according to direction
        if (d == 0) {y = y - 1;} else {y = y + 1;}
        
    // change direction when limit is reached
        if (y > 450) {d = 0;}
        if (y < 10) {d = 1;}
    
    
    Problem is, the screen is drawn correctly the first time,
    and is never refreshed.
    How to I get it to cycle?
    This is happening in the drawRect function from the Quartz line draw sample code
    Code:
    - (void)drawRect:(CGRect)rect {
    
    Cheers, Art.
     
  2. ArtOfWarfare macrumors 604

    ArtOfWarfare

    Joined:
    Nov 26, 2007
    #2
    The screen will refresh shortly after "setNeedsDisplay" is set to yes. That's the code that says "hey, when you have a moment, update what the screen looks like." also, if you can, "setNeedsDisplay:inRect:" is more efficient, as it'll only redraw in the area covered by the rect you specify.
     
  3. xArtx thread starter macrumors 6502a

    Joined:
    Mar 30, 2012
    #3

    Problem is,
    If I add this anywhere:

    Code:
    setNeedsDisplay:YES;
    
    I get an error: Expression result unused

    or

    Code:
    setNeedsDisplay;
    
    Use of undeclared identifier "setNeedsDisplay".

    How was the screen drawn once without it?
    In the above example in the first post, the text is printed to wherever
    I initialise the y variable... ie. int y = 400.
    Cheers, Art.
     
  4. admanimal macrumors 68040

    Joined:
    Apr 22, 2005
    #4
    setNeedsDisplay is a method in UIView. Therefore, to call it, you need a reference to a view. If you have one called myView, you use it like this:

    Code:
    [myView setNeedsDisplay];
    The view knows to draw itself when it appears, which is why you normally don't have to call this method.
     
  5. ArtOfWarfare macrumors 604

    ArtOfWarfare

    Joined:
    Nov 26, 2007
    #5
    needsDisplay is a variable that views have. It is automatically set to true when it is first created. When needsDisplay is true, the system will call drawRect on the view as soon as it can, and then set the variable to false. Thus, if you'd like to update the view again, you'll need to set needsDisplay to true again.
     
  6. xArtx thread starter macrumors 6502a

    Joined:
    Mar 30, 2012
    #6
  7. Scott90 macrumors 6502

    Joined:
    Jul 14, 2008
  8. angusmcbagpipes, May 1, 2012
    Last edited: May 1, 2012

    angusmcbagpipes macrumors newbie

    Joined:
    May 1, 2012
    #8
    Was this question resolved?

    I am new to xcode4/objective-c, and I'm seeing the exact same problem.

    I have two tabs, one tab accepts input and another tab draws a graph based in the historical and most recent input.

    The tab containing the graph updates correctly when the app is first run. But it does not update again.

    Does anyone have any ideas about how to cause the redraw to happen each time the tab with the graph is selected?
     
  9. ArtOfWarfare macrumors 604

    ArtOfWarfare

    Joined:
    Nov 26, 2007
    #9
    set setNeedsDisplay to true for the UIView your graph is in whenever you want it to be refreshed.

    The person who started the topic's issue seems to be that they don't know how to properly format Obj-C code.
     
  10. angusmcbagpipes macrumors newbie

    Joined:
    May 1, 2012
    #10
    My confusion is about where to setNeedsDisplay.

    I did two things which appear to have worked.

    1. I added [self.myBPGraphOutlet drawRect:tmpRect]; to the viewDidAppear of the containing UIViewController.

    2. I added [self setNeedsDisplay]; to the drawRect of the UIView that needs to be redrawn.

    This appears to do the correct thing. But, being new to xCode and Objective-C I am a little unsure if this is the correct way to do this.

    Does this seem correct to you?

    Note:

    myBPGraphOutlet is the name of the UIView.
    tmpRect is a rectangle that outlines the UIView.
     
  11. ArtOfWarfare macrumors 604

    ArtOfWarfare

    Joined:
    Nov 26, 2007
    #11
    setNeedsDisplay should be called when something on screen needs to be refreshed. When setNeedsDisplay is true, the system will call drawRect at the next moment that's most convenient (IE, to ensure no screen tears, where the system only manages to draw half of what it should have.)

    Normally, you would have a model, view, and a controller. Let's suppose, for example, that the model contains some raw data. The view would have some code that says how the data should be drawn (IE, it could have methods for how to make a pie chart for the data.) The controller would then watch the data for changes (through KVO) and then set NeedsDisplay to true for the view, so that the view knows the data has changed and it needs to update itself.

    The view shouldn't really be responsible for setting needsDisplay on itself, I don't think. Certainly you wouldn't do that inside of drawRect as that would just result in an infinite loop. (Having setNeedsDiplay be true calls drawRect, which then sets NeedsDisplay as true again, and on and on.)
     
  12. PhoneyDeveloper macrumors 68030

    PhoneyDeveloper

    Joined:
    Sep 2, 2008
    #12
    Never call drawRect. It's called for you by the system when it's time to draw.

    In most cases it's best for a custom view to call [self setNeedsDisplay] when the view's data model changes. It's never required to call setNeedsDisplay on any UIKit standard views for example. If you setText: on a UILabel the label redraws itself. If you setImage: on a UIImageView the image view redraws itself. Your views should work the same way. setMyData: calls [self setNeedsDisplay]. The controller sets the data for the custom view but never has to call setNeedsDisplay. The only example I can think of offhand that works differently is UITableView, which has a reloadData method, but it's much more complicated than the other standard views.
     
  13. angusmcbagpipes, May 4, 2012
    Last edited by a moderator: May 4, 2012

    angusmcbagpipes macrumors newbie

    Joined:
    May 1, 2012
    #13
    Thanks for the replies. They are very helpful.

    I removed the setNeedsDisplay from drawRect.

    I removed the code that called drawRect manually, and replaced it with:

    Code:
    [self.myBPGraphOutlet setNeedsDisplay];
    Not only does that work, it got rid of some errors that were going to the console.

    This is all working correctly now :)

    In case you are curious... I have a tabbed application. In the first tab the user can enter some medical data. In the second tab there is a graph of the data over time. So if the user goes back to the first tab and adds new data, the graph on the second tab needs updating.

    So by adding:

    Code:
    [self.myBPGraphOutlet setNeedsDisplay];
    To viewDidAppear in the secondViewController it forces the redraw. Technically this could force some un-necessary redraws, but the redraws are very simple and fast, so I'm not too worried.

    Thanks again guys.
     

Share This Page