• Open Menu Close Menu
  • Apple
  • Shopping Bag
  • Apple
  • Mac
  • iPad
  • iPhone
  • Watch
  • TV
  • Music
  • Support
  • Search apple.com
  • Shopping Bag

Lists

Open Menu Close Menu
  • Terms and Conditions
  • Lists hosted on this site
  • Email the Postmaster
  • Tips for posting to public mailing lists
Re: Strange NSZombie occurring
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: Strange NSZombie occurring


  • Subject: Re: Strange NSZombie occurring
  • From: Fritz Anderson <email@hidden>
  • Date: Sun, 07 Aug 2011 10:10:48 -0500

Is this really your code? There are some oddities that make me wonder.

Also, your subject line talks about NSZombie (an instance of a class that gets substituted into an object when it is released, if you have NSZombieEnabled set), but your complaint is that a property is nil when you don't expect it. That has nothing to do with zombies.

Let me annotate your example, as I think the problem might be clearer if the code were cleaner:

On 7 Aug 2011, at 8:10 AM, Scott Steinman wrote:

> -(void)setUp;
> -(void)start;
> -(void)changeWords:(NSTimer*)theTimer;
> -(NSArray *)wordsInPhrase:(NSString *)thePhrase;
> @property (nonatomic, assign) int numWords;
> @property (nonatomic, assign) NSUInt wordChangeInterval;

Here's my first reason to believe you haven't provided your real code. There is no such thing as an NSUInt. I understand your desire to provide a compact example, but we can't help you if it hides your problem. And, getting the example to compile and run may point you to your bug.

> @property (nonatomic, copy) NSString *phrase;
> @property (nonatomic, copy) NSArray *words;

Properties: Tell us whether you've backed them explicitly with instance variables, or allowed @synthesize to generate instance variables; whether the backing ivars have the same name as the properties; and whether you're providing getters or setters for any of them.

Given that we're not seeing your actual code, I don't know whether you're assigning nil to ->words or .words somewhere. Try overriding

-(void) setWords: (NSArray *) newWords
{
	if (newWords != words) {
		[words release];
		words = [newWords copy];
	}
}

and setting a breakpoint at the beginning. Extra points for conditioning the breakpoint on newWords == nil. When the breakpoint hits, examine the backtrace. It won't catch your overuse of direct access to backing ivars (a major theme of this message), but it will be something.

> @property (nonatomic, copy) NSTimer *wordChangeTimer;

NSTimer doesn't implement <NSCopying>, as copying an NSTimer doesn't make sense. If you had actually used the property, the runtime would have caught this for you.

> - (id)init
> {
>   self = [super init];
>   if (self) {
>       phrase = [[NSString stringWithString:@"This is the phrase to display"] retain];

phrase = @"This is the phrase to display";    //  stringWithString: is almost never what you intend.

[@"This is the phrase to display" copy] is the prudent thing to do, but not idiomatic or necessary.

>       wordChangeInterval = 0.2;

This was declared as "NSUInt", I assume is some sort of integer. The ivar will be set to zero.

>   }
>   return self;
> }
>
> -(void)setUp
> {
>   words = [[self wordsFromPhrase:phrase]] retain];

Your brackets are unbalanced.

self.words = [self wordsFromPhrase: self.phrase];

1. You've got a property. Use it.

2. You're simulating* the retain attribute, when your property declaration said you want copy. This suggests to me that you don't mean it.

* ("Simulating" in that you're leaking the previous occupant of ->words. The synthesized accessor would have taken care of that.)

>   [self start];

Do you ever want to change .words without doing [self start]? If not, make the call to -start inside setWords:. Then self.words = [self wordsFromPhrase: self.phrase] can completely replace -setUp. But see:

> }
>
> -(NSArray *)wordsInPhrase:(NSString *)thePhrase
> {

Perchance, do you call this method with any phrase other than self.phrase? If not, then you can implement -(NSArray *) words to return [self wordsFromPhrase: self.phrase], the property can become readonly, and your worry about self.words being nil goes away.

>   NSArray *wordArray;
>
>   [wordArray arrayByAddingObjectsFromArray:[phrase componentsSeparatedByString:@" "]];

This sentence no verb. wordArray has no initial value, so sending arrayByAddingObjectsFromArray: to it should crash most of the time (another reason I don't believe you're showing your code). arrayByAddingObjectsFromArray: returns an NSArray*, but you're throwing away the returned value, and the method itself has no side effects.

And thePhrase isn't used anywhere in the method.

>   numWords = [wordArray count];

self.numWords = wordArray.count;    // Use the property.

>   return wordArray;
> }

I _think_ you mean:

- (NSArray *) wordsInPhrase: (NSString *) thePhrase
{
	NSArray *	wordArray = [thePhrase componentsSeparatedByString: @" "];
	self.numWords = wordArray.count;
	return wordArray;
}

But I'm _guessing_ you mean:

- (NSArray *) wordsInPhrase
{
	NSArray *	wordArray = [self.phrase componentsSeparatedByString: @" "];
	self.numWords = wordArray.count;
	return wordArray;
}

and that you _really_ mean:

@property(nonatomic, readonly) NSUInteger numWords;
@property(nonatomic, readonly) NSArray *words;
@property(nonatomic, retain) NSArray * backingWordsArray;
...
@synthesize backingWordsArray;

- (NSArray *) words
{
	if (! self.backingWordsArray)
		self.backingWordsArray = [self.phrase componentsSeparatedByString: @" "];
	return self.backingWordsArray;
}

- (NSUInteger) numWords { return self.words.count; }

- (void) setPhrase: (NSString *) newPhrase
{
	if (newPhrase != phrase) {
		[phrase release];
		phrase = [newPhrase copy];
		self.backingWordsArray = nil;
		[self start];
	}
}

> - (void) start
> {
>   currentWordIndex = 0;

This won't compile from the code you're showing. Is it an ivar?

>   wordChangeTimer = [[NSTimer scheduledTimerWithTimeInterval:wordChangeInterval

[My customary objection to accessing an ivar directly.]

>                                                       target:self
>                                                     selector:@selector(changeWords:)
>                                                     userInfo:nil
>                                                      repeats:YES] retain];

self.wordChangeTimer = [NSTimer ... repeats: YES];

If you let the property manage your memory, you won't have to do it yourself. And if you have a setter method, you can invalidate the old timer.

> }
>
> - (void)changeWords:(NSTimer*)theTimer
> {
>   currentWordIndex += 1;
>   if (currentWordIndex > numWords)
>       currentWordIndex = 0;
>   messageLayer.string = [self.words objectAtIndex:currentWordIndex];
> }

For once you're actually using the property. If this is the only time, one has to wonder whether there is a -words method that doesn't do what you think it does.

> Now, the strangeness: words exists and is OK in setUpDisplay and startDisplay in that it contains the right words from the phrase.  But in changeWords:, somehow words is nil. I'm at a loss to figure out how words could be released between start and changeWords:. I'd appreciate some help.

What are setUpDisplay and startDisplay? Are they the same as setUp and start?

A property going nil is not the same as releasing the object it once pointed to. The two leading candidates for the bug are:

* There has been an assignment. At the very minimum, override setWords:, be religious about using .words as a property, and audit where the setter is called.

* There is a -words getter, in the class or its parent, that does not reflect the backing ivar. Switching to near-exclusive access through the property (except in an init..., dealloc,** or the accessors themselves) may cure it; or using my suggestion of dropping most of the ivars and computing the properties on-demand; may cure the problem.

	— F

** (Opinions differ on whether inits or dealloc should use accessor methods or the ivars that implement them. I feel strongly about the latter. See the archives for the religious wars.)

_______________________________________________

Cocoa-dev mailing list (email@hidden)

Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com

Help/Unsubscribe/Update your Subscription:

This email sent to email@hidden

References: 
 >Strange NSZombie occurring (From: Scott Steinman <email@hidden>)

  • Prev by Date: Re: Strange NSZombie occurring
  • Next by Date: Re: NSImageView vs IKImageView
  • Previous by thread: Re: Strange NSZombie occurring
  • Next by thread: iTunes Sidebar
  • Index(es):
    • Date
    • Thread