Become a MacRumors Supporter for $50/year with no ads, ability to filter front page stories, and private forums.

Blakeasd

macrumors 6502a
Original poster
Dec 29, 2009
643
0
Hello,

I am having trouble with NSWindow resizing. I have an NSWindow with an NSView subclass on top of it that fills the entire window. I am drawing this view like so:

Code:
- (id)initWithFrame:(NSRect)frame
{
    self = [super initWithFrame:frame];
    if (self) {
        customBackgroundColor = [NSColor colorWithPatternImage:[NSImage imageNamed:@"background-dark.tiff"]];
    }
    return self;
}

- (void)drawRect:(NSRect)dirtyRect
{
	[super drawRect:dirtyRect];
	
    NSGraphicsContext *contetx = [NSGraphicsContext currentContext];
    [contetx saveGraphicsState];
    [[NSGraphicsContext currentContext]setPatternPhase:NSMakePoint(0, [self frame].size.height)];
    [customBackgroundColor set];
    NSRectFill([self bounds]);
    [contetx restoreGraphicsState];
    

}

When I attempt to resize my window. I get EXC_BAD_ACCESS (code = 1, address=0x13) on [customBackgroundColor set];

Does anyone know what's going on here?

Thanks!
 
Call to Superclass

Why are you telling the superclass to draw its rect?

[super drawRect:dirtyRect];

Try it without this line.
 
I moved

Code:
    customBackgroundColor = [NSColor colorWithPatternImage:[NSImage imageNamed:@"background-dark.tiff"]];

to drawRect: and it works now. As I'm aware EXC_BAD_ACCESS means that an object has been referenced that has already been released. Why would customBackgroundColor be released once the window is resized if it is created and given a value in initWithFrame?
 
Why would customBackgroundColor be released once the window is resized if it is created and given a value in initWithFrame?

Do you own the value assigned to customBackgroundColor? If you understand retain/release you should be able to answer this. If not, you need to study retain/release memory management.

If customBackgroundColor is a property, and not just a private instance variable, then does it have a strong or weak attribute?

Are you using ARC or not?

Are you assigning using the property, or are you storing directly into the instance variable? Which one is correct for the declaration in your class header (which you haven't shown), and your chosen memory mgmt model (ARC or retain/release)?
 
I took your advice and read Apple's Advanced Memory Management Programming Guide

Here is my understanding of what happened:

I don't own the customBackgroundColor because I didn't use a method whose name began with alloc, new, copy, etc. on it. customBackgroundColor is an instance variable and I'm using ARC. Because I don't own the object, the compiler will remove references to the object once it has been used.

Am I correct?

I put the line back in initWithFrame: to practice memory management. Under the line I added:

Code:
[customBackgroundColor retain];

so the object won't get its references removed. I no longer get the exception when the window resizes, but the background is just black where a new part of the window is revealed.

What am I doing incorrectly? Thanks!
 
I took your advice and read Apple's Advanced Memory Management Programming Guide

Here is my understanding of what happened:

I don't own the customBackgroundColor because I didn't use a method whose name began with alloc, new, copy, etc. on it. customBackgroundColor is an instance variable and I'm using ARC. Because I don't own the object, the compiler will remove references to the object once it has been used.

Am I correct?

I put the line back in initWithFrame: to practice memory management. Under the line I added:

Code:
[[COLOR="red"]customBackgroundColor retain[/COLOR]];

so the object won't get its references removed. I no longer get the exception when the window resizes, but the background is just black where a new part of the window is revealed.

What am I doing incorrectly? Thanks!

Something doesn't make sense here (red hilites). Direct calls to retain and release are forbidden under ARC. At the very least, they should produce warnings, and it's far more likely they'll produce errors.
http://en.wikipedia.org/wiki/Automatic_Reference_Counting

If retain works, and has no warnings or errors, then I suspect you aren't actually using ARC.

If you really are using ARC, then you ought to learn about strong and weak property attributes. Start here:
https://developer.apple.com/library...sitioningToARC/Introduction/Introduction.html

Be sure to read the "ARC Enforces New Rules" heading in the ARC transition guide. Among other things, it says:
You cannot explicitly invoke dealloc, or implement or invoke retain, release, retainCount, or autorelease.

You should then consider studying a tutorial or book that specifically uses ARC, because it's not necessarily a simple subject for beginners.
 
Whoops, I wasn't using ARC. Why then would my object's pointer have been relinquished? I though that it is up to the developer to release variables manually (by calling [mObj release]) If I never called that then why was it's pointer removed?

Is it not possible to put that code in initWithFrame: ? I just switched it to ARC and tried to do it by giving a property (strong) to my instance variable. I don't get the EXC_BAD_ACCESS, but like when I retained the variable without ARC, the window just paints black when it is resized.

Am I missing something obvious or not so obvious?

Thanks
 
Whoops, I wasn't using ARC. Why then would my object's pointer have been relinquished? I though that it is up to the developer to release variables manually (by calling [mObj release]) If I never called that then why was it's pointer removed?

Is it not possible to put that code in initWithFrame: ? I just switched it to ARC and tried to do it by giving a property (strong) to my instance variable. I don't get the EXC_BAD_ACCESS, but like when I retained the variable without ARC, the window just paints black when it is resized.

Am I missing something obvious or not so obvious?

Thanks

[NSColor colorWithPatternImage] most likely returns an autoreleased object. It is released when you exit the current autorelease pool. Which is most likely when you exit the current event handler.
 
Am I missing something obvious or not so obvious?

You missed all the parts in the Advance Memory Management guide where it discussed ownership, the rules of ownership, and how to tell which methods return objects you don't own. Read the whole document, not just isolated parts of it. Understand the principle (ownership), not the details of the implementation (reference counting, autorelease pools, etc.).

For example, on the first page:
https://developer.apple.com/library...onceptual/MemoryMgmt/Articles/MemoryMgmt.html

is this:
Thinking about memory management from the perspective of reference counting, however, is frequently counterproductive, because you tend to consider memory management in terms of the implementation details rather than in terms of your actual goals. Instead, you should think of memory management from the perspective of object ownership and object graphs. [Emphasis added.]

It is absolutely essential that you understand ownership in order to fully understand the rules of retain/release memory management. Ownership is the fundamental principle underlying the whole edifice.



[NSColor colorWithPatternImage] most likely returns an autoreleased object. It is released when you exit the current autorelease pool. Which is most likely when you exit the current event handler.
That method follows the usual convention. So it's not "most likely", it's definite: the returned object is not owned by the caller.
 
it's definite: the returned object is not owned by the caller.

Why can't I take the ownership of the returned autoreleased object by calling retain (assuming a project is non-ARC)? Wouldn't that then make me responsible for relinquishing pointers to the object -- rather than the compiler?

If what I stated above is correct, then how do I solve the problem with an ARC project. I used strong for a property as you saw before, but the same issue occurred. As I've read on stack overflow: "strong is an exact synonym for retain."

Is the problem that I still don't have the ownership of that object despite calling retain in my non-arc project and a strong property in my arc project?

If I am taking ownership and the objects are indeed being nullified after the auto-release pool is exited, does that mean there is no such a way to put that method into init: and it must go into drawRect: ?
 
Why can't I take the ownership of the returned autoreleased object by calling retain (assuming a project is non-ARC)? Wouldn't that then make me responsible for relinquishing pointers to the object -- rather than the compiler?
You can, and it does.

Is the problem that I still don't have the ownership of that object despite calling retain in my non-arc project and a strong property in my arc project?
No one can evaluate or diagnose your latest problem because you haven't posted any revised code. It's remarkably error-prone and difficult to debug problems using isolated code fragments and descriptions alone.

See my recent post on another thread regarding partial code. The same things apply here.


Also, what else have you tried? Did you try commenting out the setPatternPhase: call? Did you try any simplification at all? For example, did you try a plain solid color instead of a pattern?

And where did you get the example for your drawRect: method?
 
Interface:

Code:
@interface BackgroundView : NSView{

    NSColor *customBackgroundColor;
   

}
@property(strong)NSColor *customBackgroundColor;

@end

Implementation:

Code:
@implementation BackgroundView
@synthesize customBackgroundColor = customBackgroundColor;
- (id)initWithFrame:(NSRect)frame
{
    self = [super initWithFrame:frame];
    if (self) {
        customBackgroundColor = [NSColor colorWithPatternImage:[NSImage imageNamed:@"background-dark.tiff"]];
     
    }
    return self;
}

- (void)drawRect:(NSRect)dirtyRect
{
	[super drawRect:dirtyRect];
	
    
    NSGraphicsContext *contetx = [NSGraphicsContext currentContext];
    [contetx saveGraphicsState];
    [[NSGraphicsContext currentContext]setPatternPhase:NSMakePoint(0, [self frame].size.height)]; 
    [customBackgroundColor set];
    NSRectFill([self bounds]);
    [contetx restoreGraphicsState];
    

}

@end


I've also tried making the color a simple [NSColor blueColor]; I get the same result -- new portions of the window revealed after resizing are black -- not blue.

The drawRect: code is not from an example. I wrote it myself.

Hopefully, this can provide some more clues.
 
The drawRect: code is not from an example. I wrote it myself.

Is ARC enabled or not?

What references did you read before writing this drawRect: method? Be specific.

Looking here:
https://developer.apple.com/library...//apple_ref/doc/uid/TP40003290-CH203-BCIJFBJJ

I see the following in their sample drawRect: method:
  1. The sample doesn't call super drawRect:.
  2. The sample doesn't call saveGraphicsState or restoreGraphicsState.
I think you ought to look at the linked reference, reading the whole document very carefully. I also think you should look at any sample code referenced by the NSGraphicsContext class reference, and discover exactly how drawRect: works in known-working examples.


EDIT
A simple example:
http://www.fruitstandsoftware.com/blog/2009/12/custom-drawing-using-drawrect-part-1/

It fills the entire custom view's bounds with the color blue.

It's from 2009, so the specific steps in Xcode are outdated.
 
Last edited:
Interface:

Code:
@interface BackgroundView : NSView{

    NSColor *customBackgroundColor;
   

}
@property(strong)NSColor *customBackgroundColor;

@end

Implementation:

Code:
@implementation BackgroundView
@synthesize customBackgroundColor = customBackgroundColor;
- (id)initWithFrame:(NSRect)frame
{
    self = [super initWithFrame:frame];
    if (self) {
        [color=red]customBackgroundColor = [NSColor colorWithPatternImage:[NSImage imageNamed:@"background-dark.tiff"]];[/color]
     
    }
    return self;
}
…
The code in red is probably your issue. Unless you are using ARC, you should do this:
Code:
[color=red]self.[/color]customBackgroundColor = [NSColor colorWithPatternImage:[NSImage imageNamed:@"background-dark.tiff"]];
Due to the @property and @synthesize methods you have used, the "self.customBackgroundColor =" calls a setter that automatically retains the value passed to it.

If you want to be a good memory citizen, add this to the dealloc call:
Code:
self.customBackgroundColor = nil;
Views on OS X are rarely released, but better safe than sorry.
Note that you do not need to put this in your dealloc call if you are using ARC.
 
Register on MacRumors! This sidebar will go away, and you'll see fewer ads.