UPDATE: I realized that the "initWithFrame" method is never called, so I placed my array's init elsewhere. Thanks for reading. (for anyone, what's the point of initWithFrame if it is not called?"
I've been staring at this code for about an hour and am probably missing a simple and obvious issue. I'm merely trying to keep an array of touched points. My UIView's init says this:
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
// Initialization code
}
self.drawn=[[NSMutableArray alloc] init ];
return self;
}
Then I have this in another method:
CGPoint point=[[touches anyObject] locationInView:self];
NSLog(#"touched point: %f, %f",point.x,point.y);
[self.drawn addObject:[NSValue valueWithCGPoint:point]];
The NSLog confirms that "point" exists and contains x and y data.
Why then does my "drawn" array never get anything? I have read the NSValue tutorials and I seem to be doing this correctly. An NSLog of [self.drawn count] always shows 0 despite that this code has triggered.
And of course "drawn" is also an ivar of my custom UIView, properly synthesized also.
Your initWithFrame: never gets called,* and drawn is never created. From the Resource Management Guide:
In iOS, any object that conforms to the NSCoding protocol is initialized using the initWithCoder: method. This includes all subclasses of UIView[...] Custom views in iOS do not use the initWithFrame: method for initialization.
The value at drawn is therefore nil, and calling [nil count] gives 0; [nil addObject:] similarly does nothing.
That said, your initWithFrame: also has two memory problems. Your assignment to the property over-retains the array, and you should be doing that assignment inside the if block.
When you create an NSMutableArray using alloc/init, you own that array. When you then assign it using a property which is defined as retaining, you have an extra claim on that object, which can eventually cause a leak.
Second: if, for whatever reason, the call to [super initWithFrame:frame] fails, self will be invalid (nil), and using one of its properties will likewise be incorrect. That's the purpose of if(self).
You should do this instead:
if(self){
self.drawn = [NSMutableArray array];
}
This creates an autoreleased NSMutableArray which your view then properly retains.
*I wish I knew why too. It does get used in OS X.
I would check if the
- (id)initWithFrame:(CGRect)frame
is called.
Related
I am doing my project in xcode 4.2 (Older Version). For my application, I just set the variables, arrays in dto class for using in entire app lifecycle. so I set with a property like this.
AppDTO(sub class of NSObject)
AppDTO.h
#property(nonatomic,retain)anotherAppDTO *aAppDTO;
#property(nonatomic,retain)NSMutableArray *array1;
#property(nonatomic,retain)NSMutableArray *array2;
#property(nonatomic,retain)NSString *string1,*string2,*string3;
AppDTO.m
- (id)init
{
self = [super init];
if (self) {
self.aAppDTO = [[anotherAppDTO alloc]init];
self.array1 = [[NSMutableArray alloc]init];
self.array2 = [[NSMutableArray alloc]init];
self.string1 = #"Hello";
self.string2= #"Hai";
}
}
-(void)dealloc
{
if(array1 != nil)
{
[array1 release];
array1 = nil;
}
if(array2 != nil)
{
[array2 release];
array2 = nil;
}
[aAppDTO release];
aAppDTO = nil;
[super dealloc];
}
when I analyze my app in Xcode 4.3.2, I get memory warning in self.array1 and self.array2 (Potential leak on object allocated on line….), but when I change self.array1 to array1, warning goes away.
What is the reason for using self. do I need to use self if I set #property(nonatomic,retain) to variables(like array1,array2,string1,string2).
Also in dealloc method, I heard we don't want to use [self.array1 release], instead we can use [array1 release]. Is it Correct?
Do I need to release my string in dealloc method.
Also I am releasing aAppDTO in dealloc method. if I allocate some objects in anotherAppDTO class, will it release automatically when I call [aAppDTO release] method.
Can anyone clarify me.
Many Thanks,
Anish
You get the warning because when you write :
self.array1 = [[NSMutableArray alloc]init];
is the same as :
[self setArray1: [[NSMutableArray alloc]init]];
As you can notice you are not allocating the underlying array1 private variable, but you are calling the setter of the property that since it is declared as retain it retains the object once assigned, this means that when you eventually will assign another object the second time with the setter the first object will remain with a retain count of one until the application will be closed (since you don't have any reference to that object anymore ...) .
Take a look at this great article to understand better Manual Reference Counting in Objective-C .
when i analyze my app in Xcode 4.3.2, i get memory warning in self.array1 and self.array2 (Potential leak on object allocated on line….), but when i change self.array1 to array1, warning goes away.
the analyzer's right. the parameter is retained when set. as well, you should favor direct access in initialization and dealloc. so, you should just write array1 = [[NSMutableArray alloc] init];, and be done.
What is the reason for using self. do i need to use self if i set #property(nonatomic,retain) to variables(like array1,array2,string1,string2).
those go through the accessor methods. if not in initialization or dealloc, you should favor going through the accessor methods because that is the common correct execution path for a fully constructed object.
Also in dealloc method, i heard we don't want to use [self.array1 release], instead we can use [array1 release]. Is it Correct?
correct.
Do i need to release my string in dealloc method.
yes.
Also I am releasing aAppDTO in dealloc method. if i allocate some objects in anotherAppDTO class, will it release automatically when i call [aAppDTO release] method.
when its reference count reaches 0, its dealloc will be called.
I think the others have answered your question.
I do want to draw your attention to Apple's excellent Advance Memory Management Programming Guide: Practical Memory Management, in which they walk through these sorts of scenarios. It's hard to take it all in on the first reading, but it really does cover this stuff. In answer to your question about the use of instance variables versus the accessor methods, I draw your attention to the section labeled to "Don't Use Accessor Methods in Initializer Methods and dealloc".
I thought I understood memory management well enough until this issue happened (Mac OS X 10.6): I have a custom NSView subclass with an NSMutableArray instance variable, but when I dealloc my view and attempt to release that instance variable, sometimes BOOM, EXC_BAD_ACCESS happens. This happens when I try to close my document window without quitting the program, but for some reason, even under identical conditions, sometimes it works without issue. Can anyone help me understand what's going on here? The relevant bits of code from my NSView subclass:
- (id)initWithFrame:(NSRect)frame {
self = [super initWithFrame:frame];
if (self) {
rainbow = [[NSMutableArray alloc] initWithObjects:
// some objects go here, followed by the nil sentinel
]
return self;
}
return nil;
}
And the dealloc method:
- (void)dealloc {
[super dealloc];
NSLog(#"Release the rainbow!");
if (rainbow) {
[rainbow removeAllObjects]; // EXC_BAD_ACCESS happens here
[rainbow release];
}
}
Even though I check whether rainbow is still around, sending it a message results in that segfault. There is one spot where it gets used: it's passed as a *info argument to a CGShading callback function. Here are the relevant bits of that function (which generally works without crashing):
NSMutableArray *colorStops = (NSMutableArray *)info;
[colorStops retain];
/*
...
*/
[colorStops release];
I'm guessing that there's something here about threads, but I really don't know. Anyone have any ideas? Thank you very much! I've reread the memory management guide; any more headdesking on this and my glass tabletop shatters in my face.
Always do
[super dealloc]
at the end of your dealloc method.
In addition to Terry's point about [super dealloc], the -removeAllObjects call will message all of the objects in the array (to release them). If you have overreleased any of those objects, the pointer that the array has may now point to deallocated or otherwise invalid space.
So, you have to review your memory management of all of the objects in the array. Run your app under the Zombies instrument. Do a Build and Analyze and resolve the identified issues.
In objective c, suppose I have an object Obj stored in a NSMutableArray, and the array's pointer to it is the only strong pointer to Obj in the entire program. Now suppose I call a method on Obj and I run this method in another thread. In this method, if Obj sets the pointer for itself equal to nil will it essentially delete itself? (Because there will be no more strong pointers left) I suspect the answer is no, but why? If this does work, is it bad coding practice (I assume its not good coding, but is it actually bad?)
It is highly unlikely that an object would be in a position to cause its own release/deallocation if your code is designed properly. So yes, the situation you describe is indicative of bad coding practice, and can in fact cause the program to crash. Here is an example:
#interface Widget : NSObject
#property (retain) NSMutableArray *array;
#end
#implementation Widget
#synthesize array;
- (id)init
{
self = [super init];
if(self) {
array = [[NSMutableArray alloc] init];
[array addObject:self];
}
return self;
}
- (void)dealloc
{
NSLog(#"Deallocating!");
[array release];
[super dealloc];
}
- (void)removeSelf
{
NSLog(#"%d", [array count]);
[array removeObject:self];
NSLog(#"%d", [array count]);
}
#end
and then this code is in another class:
Widget *myWidget = [[Widget alloc] init];
[myWidget release]; // WHOOPS!
[myWidget removeSelf];
The second call to NSLog in removeSelf will cause an EXC_BAD_ACCESS due to the fact that array has been deallocated at that point and can't have methods called on it.
There are at least a couple mistakes here. The one that ultimately causes the crash is the fact that whatever class is creating and using the myWidget object releases it before it is finished using it (to call removeSelf). Without this mistake, the code would run fine. However, MyWidget shouldn't have an instance variable that creates a strong reference to itself in the first place, as this creates a retain cycle. If someone tried to release myWidget without first calling removeSelf, nothing would be deallocated and you'd probably have a memory leak.
If your back-pointer is weak (which it should be since a class should never try to own it's owner, you will end up with a retain-cycle) and you remove the strong pointer from the array the object will be removed from the heap. No strong pointers = removed from memory.
You can always test this.
If you need a class to bring to a situation where its deleted, the best practice is to first retain/autorelease it and then make the situation happen. In this case the class won't be deleted in a middle of its method, but only afterwards.
I think we can say it might be bad coding practice, depending on how you do it. There are ways you could arrange to do it safely, or probably safely.
So let's assume we have a global:
NSMutableArray *GlobalStore;
One approach is to remove yourself as your final action:
- (void) someMethod
{
...
[GlobalStore removeObject:self];
}
As this is the final action there should be no future uses of self and all should be well, probably...
Other options include scheduling the removal with a time delay of 0 - which means it will fire next time around the run loop (only works of course if you have a run loop, which in a thread you may not). This should always be safe.
You can also have an object keep a reference to itself, which produces a cycle and so will keep it alive. When its ready to die it can nil out its own reference, if there are no other references and that is a final action (or a scheduled action by another object) then the object is dead.
I am making a game (obviously) and I noticed that my HelloWorldLayer.m file is getting EXTREMELY cramped. I KNOW that there is a way to run methods from other .m files, I just don't know how. For example, I want to have a Character.h and Character.m file. Can I make it so in the HelloWorldLayer init layer, it just uses everything from the Character files instead of having to declare everything in the HelloWorldLayer? I hope my question makes sense, and any help is appreciated. Thanks!
Here is Character.m:
#implementation Character
#synthesize health,velocity;
-(void)dealloc {
[super dealloc];
}
-(id)initWithTexture:(CCTexture2D *)texture rect:(CGRect)rect
{
if((self = [super initWithTexture:texture rect:rect]))
{
[self scheduleUpdate];
}
return self;
}
-(void)update:(ccTime)dt {
[self setPosition:ccp(self.position.x,self.position.y)];
self = [CCSprite spriteWithFile:#"nukeboyGreen.gif"];
}
#end
And here's HelloWorldLayer.m (I skimped it down and took out the parts that aren't necessary):
self = [super init];
if( (self=[super initWithColor:ccc4(255,255,255,255)] )) {
CGSize winSize = [[CCDirector sharedDirector] winSize];
character = [Character spriteWithFile:#"nukeboyGreeen.gif"];
character.position = ccp(winSize.width/2,winSize.height/2);
character.scale = 0.15;
[self addChild:character];
Note that I have a Character declared in HelloWorldLayer.h
This is where object oriented programming comes to the rescue. OOP encourages you to encapsulate variables and functions that is pertinent to an object in that object itself. In your case, you should put the methods that are specific to Character in the Character class, and only get your HelloWorld to trigger those methods.
Examples:
#interface Character : CCSprite {
...
}
- (void)didCollideWith:(Object *)object;
- (void)moveTo:(CGPoint)nextPoint;
- (void)shootArrow:(ckDirection)direction;
- (BOOL)isAlive;
- (int)numberOfLivesRemaining;
...
#end
Then in HelloWorldLayer:
[character moveTo:ccp(100, 200)];
[character shootArrow:kDirectionUp];
if (![character isAlive]) {
[self showGameOver];
}
Not only that your HelloWorldLayer is less cluttered, you can easily understand what your code does by simply looking at the reasonably named methods.
EDIT:
To answer your question as in the comment about how to designate the sprite image in Character class:
#implementation Character
- (id)init {
self = [super initWithFile:#"sprite_character.png"];
if (self) {
// further customization
}
return self;
}
#end
EDIT (after code was added to the question):
First let me point out a few mistake (sorry for the lack of softer word):
You rarely need your sprite to call the [self scheduleUpdate] or [self schedule:SEL]. Normally people implement the update (or tick) method at the CCLayer or CCScene level, where the purpose is to check all the actors (sprites, menus, nested layers etc) for collision/interaction and update their attributes. If you just want to animate movement of a sprite to a specific position, just call runAction method from CCLayer (in the init, update, ccTouchBegan or somewhere). You can read cocos2d-iphone tutorial on Actions by clicking here. So, move the update method and the scheduleUpdate call into your HelloWorldLayer, and then you no longer need to override initWithTexture.
I'm seeing you instantiating a CCSprite in the update method. My above point on the inappropriateness of update method in CCSprite notwithstanding, there is something more important you need to understand when you implement a method: that is you need to decide how and how often your method is going to be used/called. Since the update method is going to be called once per frame (that is 60 times per second), it is simply wrong to unconditionally instantiate an object in that method. You are making the iPhone to allocate (and deallocate) the object with no apparent reason, wasting the processor time/power the device has. You might want to ask where should you instantiate the CCSprite. The answer is in the init method because that method is only called once per object instance. Again, all you need to know is whether a method is going to be called once or multiple times, and decide whether a piece of code should be in there or somewhere else.
In your code for HelloWorldLayer, did you realize that you are calling the super init* methods twice. You don't need to call [super init] since [super initWithColor:ccc4( ... )] is going to call specific init method internally. Although it is not entirely wrong to do so, you are going to break the 'assumption' that init is going to be called once per instance, so you might end up breaking some object integrity unintentionally (and believe me it's going to be hard to debug later)
And finally, care to enlighten me what's the real purpose of the line [self setPosition:ccp(self.position.x,self.position.y)];. You basically set the position of the self object to its current position, so that's like saying "hey you, move your position to your current position" and he'll be like "huh?" :P
I can construct a UIImageView object with myImageView = [[UIImageView alloc] initWithImage:image];
Following application activity affecting the display, if I want to change the image on the UIImageView. I can do so by reassigning it with myImageView.image = someNewImage. However this doesn't seem to update the frame dimensions. I can modify those manually, but I have observed in practice that calling [myImageView initWithImage:someNewImage] does that for me, and has the advantage of being terser.
However I not sure if it is officially a breach of protocol in Objective C to make multiple calls to init methods on an object constructed by a single alloc. I wouldn't use it unless it was safe (guaranteed not to crash or cause leaks). Is there evidence that it is unsafe?
My research so far...
This article gives general detail about 'alloc' and 'init' on objects
http://developer.apple.com/library/mac/documentation/cocoa/Conceptual/ObjectiveC/Articles/ocAllocInit.html
This is related SO question
Why are alloc and init called separately in Objective-C?
This blog article warns suppliers of objects that their init methods may be called multiple times as an effect of the initialization process.
http://www.friday.com/bbum/2009/09/06/iniailize-can-be-executed-multiple-times-load-not-so-much/
No.
-init is written assuming that it is only called once. For example, -initWithImage quoted in Apple's documentation you quoted is implemented as
- (id)initWithImage:(NSImage *)anImage {
...
if (self) {
image = [anImage retain];
}
return self;
}
This assumes that the ivar image doesn't point to a retained object. If called twice, it leaks image.
Call -init... only once per alloc, and call -init... immediately after alloc by combining them as usual:
SomeClass* foo=[[SomeClass alloc] init...: ... ];
You should never separate them, because [anAllocedObject init...] might return something different from anAllocedObject.
No, init (or one of it's variants) should only be called once on any object, as Yuji explained. As far as your UIImageView issue goes, I believe you can just call [imageView sizeToFit] after assigning your new image, and it will automatically resize it for you.