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

ArtOfWarfare

macrumors G3
Original poster
Nov 26, 2007
9,560
6,059
I'm making a side scrolling game. When a player enters a rectangle, I would like it to trigger displaying a message.

At the start of the program, I read an XML file with this parser:

Code:
-(void)parseXMLFileAtURL:(NSURL *)file
{
	NSXMLParser *parser = [[NSXMLParser alloc] initWithContentsOfURL:file];
	[parser setDelegate:self];
	[parser setShouldProcessNamespaces:NO];
	[parser setShouldReportNamespacePrefixes:NO];
	[parser setShouldResolveExternalEntities:NO];
	[parser parse];
    
	[parser release];
}

-(void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict
{
	if ([elementName isEqualToString:@"messageTrigger"])
    {
        float x = [[attributeDict valueForKey:@"x"] floatValue];
		float y = [[attributeDict valueForKey:@"y"] floatValue];
        float w = [[attributeDict valueForKey:@"w"] floatValue];
        float h = [[attributeDict valueForKey:@"h"] floatValue];
        
        messageTriggers[messageCount] = CGRectMake(x, y, w, h);
        messages[messageCount] = [attributeDict valueForKey:@"message"];
        messageCount++;
    }
}

The XML file looks like this:

Code:
<adalez map="test" author="xxx">
    <!-- Messages -->
    <messageTrigger x="480" y="300" w="480" h="100" message="You are on a hidden platform!"/>
</adalez>

Every time the character moves it checks whether their frame intersects with the message trigger frame.

Code:
    int i;
    for (i = 0; i < messageCount; i++)
    {
        if (CGRectIntersectsRect(frame, messageTriggers[i]))
        {
            NSLog(@"Detected that you set off the message trigger.");
            NSLog(@"The message is: %@", messages[i]);
            messageLabel.text = messages[i];
            messageLabel.alpha += 0.05;
            break;
        }
        
        else messageLabel.alpha -= 0.01;
    }

It logs that I set off the message trigger, but it crashes before logging what the message is. It tells me that "Thread 1:program received signal: "EXC_BAD_ACCESS"" If I take out the log and setting the messageLable.text, it runs fine and properly shows and hides the UILabel.

Edit: In the parser I can get an NSLog that says what [attributeDict valueForKey:mad:"message"] is, and I can also get an NSLog to give me what messages[messageCount] is right afterwards. Both work fine and display the correct message.
 
Last edited:

chown33

Moderator
Staff member
Aug 9, 2009
10,750
8,422
A sea of green
Code:
-(void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict
{
	if ([elementName isEqualToString:@"messageTrigger"])
    {
        float x = [[attributeDict valueForKey:@"x"] floatValue];
		float y = [[attributeDict valueForKey:@"y"] floatValue];
        float w = [[attributeDict valueForKey:@"w"] floatValue];
        float h = [[attributeDict valueForKey:@"h"] floatValue];
        
        messageTriggers[messageCount] = CGRectMake(x, y, w, h);
[COLOR="Red"]        messages[messageCount] = [attributeDict valueForKey:@"message"];
[/COLOR]        messageCount++;
    }
}
The red-hilited code is doing nothing to claim ownership of the returned value.
Review the Memory Management Guide.

If you haven't run Build and Analyze, you should.

If you're not testing in Instruments with zombies enabled, you should.
 

ArtOfWarfare

macrumors G3
Original poster
Nov 26, 2007
9,560
6,059
Thank you :)

I can't believe I forgot to retain, now I just feel silly.

Thanks for pointing out that those tools are available.
 

covertsurfer

macrumors 6502a
Jan 18, 2007
575
5
Can you show your solution?

I am looking at this and dont understand why you need a retain because surely the dictionary's key should hold that value
 

chown33

Moderator
Staff member
Aug 9, 2009
10,750
8,422
A sea of green
Can you show your solution?

I am looking at this and dont understand why you need a retain because surely the dictionary's key should hold that value

Do you mean the attributeDict? The one passed to the method?

attributeDict isn't owned by the method, and therefore can go away at some point in the near future, perhaps even very shortly after the method returns. If the dictionary goes away, then what prevents the value from going away? Does the key claim ownership of the value, or does the dictionary?

Please review the Memory Management Guide. Also see the NSDictionary and NSMutableDictionary class reference docs for details on ownership of keys and values.
 

covertsurfer

macrumors 6502a
Jan 18, 2007
575
5
If the dictionary goes away and I'm guessing you mean released, it doesn't matter if the key owns the value because the key will be gone as the dictionary has been released??

If the dictionary goes away, then what prevents the value from going away?

In that scenario if you add a retain and the dictionary is released surely the value is gone?
 

chown33

Moderator
Staff member
Aug 9, 2009
10,750
8,422
A sea of green
If the dictionary goes away and I'm guessing you mean released,
No, "goes away" means dealloc'ed. A release doesn't always cause something to go away (be dealloc'ed). A release only causes a dealloc if there are no remaining ownership claims. The number of ownership claims is indicated by retainCount.

The whole point of having retain, release, and retainCount is so there can be multiple ownership claims for an object. Anyone can claim ownership, and the object won't go away (be dealloc'ed) until all ownership claims are removed. This is fundamental stuff from the Memory Management Guide.


it doesn't matter if the key owns the value because the key will be gone as the dictionary has been released??
It matters because ownership (who owns what) matters.


In that scenario if you add a retain and the dictionary is released surely the value is gone?
Please explain the logic for that conclusion.

Here's the explanation for that conclusion being wrong.

If the dictionary has ownership of a key and a value, and you add a retain on the value (i.e. an ownership claim), what is the total number of ownership claims on the value? 2.

If the dictionary is dealloc'ed, it releases all its ownership claims. What is the remaining number of ownership claims on the value? 1.

Whose ownership claim is it? Yours, the one you made with retain.

If someone else adds another ownership claim (calls retain), does that affect your ownership? No.

All of this is fundamental stuff from the Memory Management Guide.
 

covertsurfer

macrumors 6502a
Jan 18, 2007
575
5
Ok thanks for the explanation. I think I have it.

I also believe now why the original poster was having problems because the dictionary was getting passed in and being modified but the values were not stored because of the missing retain. In C# we call this reference parameters: if you pass something in, modify it and expect the value to be there. You have to specify a keyword "ref" if you want that functionality to work. I see in this scenario you would use the retain keyword.
 

chown33

Moderator
Staff member
Aug 9, 2009
10,750
8,422
A sea of green
Ok thanks for the explanation. I think I have it.

I also believe now why the original poster was having problems because the dictionary was getting passed in and being modified but the values were not stored because of the missing retain. In C# we call this reference parameters: if you pass something in, modify it and expect the value to be there. You have to specify a keyword "ref" if you want that functionality to work. I see in this scenario you would use the retain keyword.

The dictionary was not being modified. An NSDictionary is immutable by nature (see the class reference doc). A mutable dictionary must be an NSMutableDictionary, which is a distinct subclass, but that's not what was passed to the method.

All Objective-C objects are passed by reference. Always. There is no way to use objects any other way. If you want a copy, you have to ask for a copy (there's a protocol for this: NSCopying). If you want a mutable copy, you have to ask for that: see NSMutableCopying.

C# is garbage-collected, so drawing analogies between it and reference-counting is dubious. For example, with GC enabled (say, in Mac OS X), a retain would be unnecessary (in fact, it would do nothing), and the original code would be correct as-is.

Also, retain is a method, not a keyword. There's a big difference. Methods are overridable (among other things); keywords are not. Method names can be anything; keywords are predefined and fixed.

This has nothing to do with reference vs. non-reference types, nor mutable objects. It's purely a question of ownership and object lifetime. A modifiable (mutable) object retrieved from the dictionary would present exactly the same issues.
 

covertsurfer

macrumors 6502a
Jan 18, 2007
575
5
Ok thanks.

Below is a scenario I put together which hopefully makes sense and wondered whether I have it right.

Create new instance of class with dictionary and init it
Populate dictionary
Call method with retain for value
Now there are 2 owners of the value
Call method to release dictionary
Now 1 owner however is that an invalid pointer? Does retain create a
pointer to that value or is that value just retained in memory
separately?
release object that retained value. Now 0 owners?
Release class instance
Dealloc gets automatically called?

Also depending on what the messages object is should you not call copy rather than retain. I read you should call copy on mutable classes/objects and retain if the mutable class has a subclass of mutable ie.NSString and NSMutableString
 

chown33

Moderator
Staff member
Aug 9, 2009
10,750
8,422
A sea of green
Ok thanks.

Below is a scenario I put together which hopefully makes sense and wondered whether I have it right.
Post compilable code for scenarios, not descriptions. Code is unambiguous, even when it's wrong. Descriptions are often ambiguous or unclear.

Create new instance of class with dictionary and init it
What does "class with dictionary" mean? Does it mean an NSDictionary? NSMutableDictionary? Or a class of your own, say ExampleClass, that has a dictionary instance variable?

If it's an ExampleClass of your own, is the dictionary only an ivar, or is it a property? What attributes on the property? If not a property, how are values assigned to ivar?

What methods are used to create the dictionary? alloc and init? Or one of the convenience methods?

Populate dictionary
Is that an NSMutableDictionary? Or did you supply initial keys & objects? Where did the keys and objects come from?

Call method with retain for value
What is the value? How was it created? Who owns it to begin with?


I don't think I need to go on. Post compilable code, and all these questions and ambiguities will be resolved, because we'll see actual code.

When you post compilable code, we can compile it and see what it does. I suggest you do the same before posting it.



Does retain create a
pointer to that value or is that value just retained in memory
separately?
Did you read the Memory Management Guide? Does it say anything about retain "creating a pointer"? I don't even know what you mean by "create a pointer". A pointer is a simple address. Addresses don't have to be "created". They simply have to point to valid memory. Memory at an address needs to be initialized, if it's going to be an object. But that's not "creating a pointer", it's initializing the object's memory. And initializing the object's memory is not at all the same as retain. Please read the Memory Management Guide for what -retain does.


Also depending on what the messages object is should you not call copy rather than retain. I read you should call copy on mutable classes/objects and retain if the mutable class has a subclass of mutable ie.NSString and NSMutableString
That's an entirely different question, covering an entirely different issue.

If the object is being used in a way that mutability is a problem, such as a key in a dictionary, then -copy is proper. If mutability isn't a problem, such as a value in a dictionary, then what's proper depends on what the program intends to do with the value. For example, NSDictionary will -copy keys, but not values. Read its class reference doc, where it says this.
 
Register on MacRumors! This sidebar will go away, and you'll see fewer ads.