xcode 4.2 Message from Analyze tool - xcode

Little confused about the message from Analyze command in Xcode 4.2. It complains about the instance variable activityView.
Analyze tool complains on [self startRefresh:NULL] line about potential leak of activityView.
activityView is an instance variable, and is synthesized
I am releasing activityView in dealloc()
Per my understanding, when the setter is used (implicitly via self.activityView), the previous value is released, right?
So, I how should I read the warning from the Analyze tool? Or what changes do I need?
Thx.

Assuming the #property has the retain attribute, the setter will retain this new activity view, so you are still responsible for the +1 count from the alloc/init.
So you can do something like this:
self.activityView = [[[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleWhite] autorelease];
Just autorelease the new instance to balance out the alloc/init.
The analyzer isn't warning you about the previous value of activityView. It's warning you about the new instance, which effectively has a +2 retain count after your alloc/init and the #property (retain).

Related

iOS 10 NSNumber crash with enumerations

I am having a very weird issue relating to NSNumber objects for my enumerated values and access to them on a device running iOS os version 10.
Just as a disclaimer - this issue does not happen in other iOS os versions.
I have declared an enum like so:
typedef NS_ENUM(NSInteger, MYENUM) {
FIRST = 1500,
SECOND = 1700,
THIRD = 1900,
...
};
When using this enum, I am passing it along in this fashion:
[[MyObject alloc] initObjectWith:#(FIRST)];
Excluding the inner logic, I am using the enum in a dictionary and thus need to convert it to a NSNumber.
While doing so, the application crashes, because the enum is somehow not a NSNumber, but rather a NSIndexPath.
Why does this happen?
When I remove the boxed literal and change the method signature to accept a NSInteger, this crash disappears.
I have tried searching online for this type of issue, but have come up short.
Further Explanation (per comment)
No special logic happens inside the init method for myObject, just assigning the property which is defined as a NSNumber to the parameter that is passed.
Regarding the crash log, Xcode is infamous in providing not so useful crash logs and all I am seeing is EXC_BAD_ACCESS, which could either mean accessing an object that has been released or a potential memory leak.
The MyObject class is defined as follows:
header file:
#interface ISNEvent : NSObject
#property(nonatomic, assign) NSNumber* number;
-(instancetype)initObjectWith:(NSNumber*)number;
#end
.m file:
- (instancetype)initObjectWith:(NSNumber*)number {
self = [super init];
if (self) {
_number = number;
}
return self;
}
You have defined your property with assign memory semantics:
#property(nonatomic, assign) NSNumber* number;
That means that you’ll get a reference to whatever you supply, but you won’t keep a strong reference and you won’t nil your reference when the object is deallocated. That’s the worse of both worlds, because you’re keeping a dangling reference to an object that you’re allowing to be deallocated. As you said, this particular error “could ... mean accessing an object that has been released”, and that’s precisely what’s going on here.
You might consider temporarily turning on zombies (command+<) or “Product” » “Scheme” » “Edit Scheme...” and go to the “Diagnostics” section of the “Run” settings, and see if your behavior changes. You’ll probably no longer see that NSIndexPath (or whatever) reference, but rather some confirmation that the NSNumber instance has been deallocated.
Anyway, you undoubtedly meant to make this NSNumber property a strong reference:
#property(nonatomic, strong) NSNumber *number;
The other solution would be to make it weak, allowing it to be deallocated, but safely setting your reference to nil. That’s safer than assign, but I also doubt that’s what you intended. And the third alternative would be copy, which is what we sometimes use with mutable types, which isn’t applicable here.
Bottom line, nowadays, I’d advise against ever using assign memory semantics with any object types. Use strong, copy, or weak. In this case, strong is what you want. Only use assign with primitive data types (e.g. NSInteger, CGFloat, etc.), but not with object types.
And, remember, when you’re done testing with the zombies, turn that diagnostic feature off.

Independently reusing a declared strong property

I created a class (MyClass) and need several instances of it, each will hold several timers, textfields and labels. Because of ARC, the target was getting deallocated when the timers were invalidated, but I sometimes invalidate them to restart them so I can't let them deallocate. So I went to my AppDelegate (which is the class that creates the instances of MyClass) and declared MyClass as a strong property. #property (strong) MyClass *myInstance; This partially works the problem is that whenever I create another instance, the previous instance loses it's reference, and if I try to restart the NSTimer in an old instance, I get BAD ACCESS. If I restart the last timer there's no problem.
I believe that since myInstance is a property, whenever I make a new one the AppDelegate rewrites the old one, losing the old references. I need to either be able to keep the strong property but somehow make it work independently for each instance, or find another way to make myInstance a strong reference, without it having to be a property.
Put your instances in a Container like NSSet or NSArray.

Debugging NSOperationQueue Blocking

I need some guidance in how to debug problems with concurrency in Cocoa under 10.6. I'm converting a 'for' loop to use NSOperations but most of the time, the code just freezes at some point through the loop. I can see NSLog output in the console to that effect. On the rare occasion, the code will run all the way through and it's fine.
The code is model-layer only, initiated from a method in the controller. The method loops through just 8-10 model objects, instructing them to each write their output to a uniquely named file. 8 model objects = 8 separate files. There are no calls up to the GUI and the model objects are NSManagedObject subclasses, which contain a set of child NSManagedObject objects (0..n of them), which each owning object summarizes and writes out. The output format is JSON.
Code:
__block NSMutableArray *collectionOfCourses = [[NSMutableArray alloc] initWithCapacity:[[self courses] count]];
/* Create a filename. Use our title and set it to lowercase */
NSURL *ourFileURL = [aURL URLByAppendingPathComponent:[[self title] lowercaseString]];
ourFileURL = [ourFileURL URLByAppendingPathExtension:#"js"];
for (Course *aCourse in [self courses]) {
[[self opQueue] addOperationWithBlock:^{
NSArray *arrayForOneCourse = [aCourse arrayAndWriteToFileURL:aURL fileFormat:format];
[collectionOfCourses addObject:arrayForOneCourse];
}];
}
I do a lot of NSLogs, would that be the issue? Is NSLog'ing from background threads a bad thing?
Since I'm adding to the mutable array from withinside a block, is it correct that I declare the mutable array as __block? I've tried it both ways and seemingly no difference relating to this freezing problem.
How do I debug this problem using Xcode v4? I want to know the line of code that it's freezing on, or what two lines of code are executing at the same time and causing it to block the execution.. My former techniques of setting a single breakpoint and stepping through the code no longer work, because of the concurrency.
thanks
It's nothing to do with your block-scoped variable. Your problem is that neither NSMutableArray nor NSManagedObject are in any way, shape or form thread-safe. You cannot do what you're doing here. If you want to have this processed off the main thread, you need to use a dispatch queue or something similar to process each item serially (and even when you're back on the main thread, you should use that same queue before you read from your mutable array. It'd probably be easier and safer, however, to do something like copy the mutable array to an immutable version when you're finished and then dispatch a notification or call-back to the main thread with the new, immutable copy embedded.

NSArrayController and KVO

What do I need to do to update a tableView bound to an NSArrayController when a method is called that updates the underlying array? An example might clarify this.
When my application launches, it creates a SubwayTrain. When SubwayTrain is initialised, it creates a single SubwayCar. SubwayCar has a mutable array 'passengers'. When a Subway car is initialised, the passengers array is created, and a couple of People objects are put in (let's say a person with name "ticket collector" and another, named "homeless guy"). These guys are always on the SubwayCar so I create them at initialisation and add them to the passengers array.
During the life of the application people board the car. 'addPassenger' is called on the SubwayCar, with the person passed in as an argument.
I have an NSArrayController bound to subwayTrain.subwayCar.passengers, and at launch my ticket collector and homeless guy show up fine. But when I use [subwayCar addPassenger:], the tableView doesn't update. I have confirmed that the passenger is definitely added to the array, but nothing gets updated in the gui.
What am I likely to be doing wrong? My instinct is that it's KVO related - the array controller doesn't know to update when addPassenger is called (even though addPassenger calls [passengers addObject:]. What could I be getting wrong here - I can post code if it helps.
Thanks to anyone willing to help out.
UPDATE
So, it turns out I can get this to work by changing by addPassenger method from
[seatedPlayers addObject:person];
to
NSMutableSet *newSeatedPlayers = [NSMutableSet setWithSet:seatedPlayers];
[newSeatedPlayers addObject:sp];
[seatedPlayers release];
[self setSeatedPlayers:newSeatedPlayers];
I guess this is because I am using [self setSeatedPlayers]. Is this the right way to do it? It seems awfully cumbersome to copy the array, release the old one, and update the copy (as opposed to just adding to the existing array).
I don't know if its considered a bug, but addObject: (and removeObject:atIndex:) don't generate KVO notifications, which is why the array controller/table view isn't getting updated. To be KVO-compliant, use mutableArrayValueForKey:
Example:
[[self mutableArrayValueForKey:#"seatedPlayers"] addObject:person];
You'll also want to implement insertObject:inSeatedPlayersAtIndex: since the default KVO methods are really slow (they create a whole new array, add the object to that array, and set the original array to the new array -- very inefficient)
- (void)insertObject:(id)object inSeatedPlayerAtIndex:(int)index
{
[seatedPlayers insertObject:object atIndex:index];
}
Note that this method will also be called when the array controller adds objects, so its also a nice hook for thinks like registering an undo operation, etc.
I haven't tried this, so I cannot say it works, but wouldn't you get KVO notifications by calling
insertObject:atArrangedObjectIndex:
on the ArrayController?
So, it turns out I can get this to work by changing by addPassenger method from
[seatedPlayers addObject:person];
to
NSMutableSet *newSeatedPlayers = [NSMutableSet setWithSet:seatedPlayers];
[newSeatedPlayers addObject:sp];
[seatedPlayers release];
[self setSeatedPlayers:newSeatedPlayers];
I guess this is because I am using [self setSeatedPlayers]. Is this the right way to do it?
First off, it's setSeatedPlayers:, with the colon. That's vitally important in Objective-C.
Using your own setters is the correct way to do it, but you're using the incorrect correct way. It works, but you're still writing more code than you need to.
What you should do is implement set accessors, such as addSeatedPlayersObject:. Then, send yourself that message. This makes adding people a short one-liner:
[self addSeatedPlayersObject:person];
And as long as you follow the KVC-compliant accessor formats, you will get KVO notifications for free, just as you do with setSeatedPlayers:.
The advantages of this over setSeatedPlayers: are:
Your code to mutate the set will be shorter.
Because it's shorter, it will be cleaner.
Using specific set-mutation accessors provides the possibility of specific set-mutation KVO notifications, instead of general the-whole-dang-set-changed notifications.
I also prefer this solution over mutableSetValueForKey:, both for brevity and because it's so easy to misspell the key in that string literal. (Uli Kusterer has a macro to cause a warning when that happens, which is useful when you really do need to talk to KVC or KVO itself.)
The key to the magic of Key Value Observing is in Key Value Compliance. You initially were using a method name addObject: which is only associated with the "unordered accessor pattern" and your property was an indexed property (NSMutableArray). When you changed your property to an unordered property (NSMutableSet) it worked. Consider NSArray or NSMutableArray to be indexed properties and NSSet or NSMutableSet to be unordered properties. You really have to read this section carefully to know what is required to make the magic happen... Key-Value-Compliance. There are some 'Required' methods for the different categories even if you don't plan to use them.
Use willChangeValueForKey: and didChangeValueForKey: wrapped around a change of a member when the change does not appear to cause a KVO notification. This comes in handy when you are directly changing an instance variable.
Use willChangeValueForKey:withSetMutation:usingObjects: and didChangeValueForKey:withSetMutation:usingObjects: wrapped around a change of contents of a collection when the change does not appear to cause a KVO notification.
Use [seatedPlayers setByAddingObject:sp] to make things shorter and to avoid needlessly allocating mutable set.
Overall, I'd do either this:
[self willChangeValueForKey:#"seatedPlayers"
withSetMutation:NSKeyValueUnionSetMutation
usingObjects:sp];
[seatedPlayers addObject:sp];
[self didChangeValueForKey:#"seatedPlayers"
withSetMutation:NSKeyValueUnionSetMutation
usingObjects:sp];
or this:
[self setSeatedPlayers:[seatedPlayers setByAddingObject:sp]];
with the latter alternative causing an automatic invocation of the functions listed under 1. First alternative should be better performing.

Dealing with objects returned from cocoa convenience methods

I'm having a lot of issues with NSDate objects being prematurely deallocated. I suspect that the issues may be related to the way that I deal with the objects returned from NSDate convenience methods. I think that my showDate property declaration in the JKShow class should be "retain", but changing it to assign or copy seems to have no effect on the issue.
JKShow *show;
NSDate *date;
NSMutableArray *list = [[NSMutableArray alloc] init];
// Show 1
show = [[JKShow alloc] init];
//...
date = [gregorian dateFromComponents:dateComponents];
show.showDate = date;
[list addObject:[show autorelease]];
// Show 2
show = [[JKShow alloc] init];
//...
date = [gregorian dateFromComponents:dateComponents];
show.showDate = date;
[list addObject:[show autorelease]];
UPDATE
The issue was not in the code copied here. In my JKShow init method I was not retaining the date returned from the NSDate convenience method. Thanks for your help, everyone.
The date returned from dateFromComponents should be in the autorelease pool, so you are correct that your showDate property should be "retain". In fact it should be anyway (unless you specifically want "copy").
From the code you have shown it looks like you are giving ownership of your show object entirely to the list (as you're setting autorelease on them as you add them). Are you saying that the date objects are being deallocated before the show objects are coming out of the list (or the list is being deallocated)?
Also, are you using synthesised properties, or are you writing them by hand? If the latter, what is your setShowDate property method like?
You can also try logging the retainCount of the date object at different places (although I always find that autorelease really complicates that).
If showDate is a retain property that should be sufficient, given the code you have posted. Something else (probably in JKShow's implementation) may not be correct.
If you want to figure out what is going on, you can use Instruments to see examine the objects lifespan. You need to run it with the allocation tool set to remember retains and releases. By default it is set up that way if you run the leaks performance tool.
When you run Instruments like that it will record all object life spans, and the backtrace for every retain and release issued against them. If you look through the objects, find one of your dates, and look at all the retains and releases you should be able to determine where the spurious release is happening.
The code you showed has no premature-release problems. In fact, it will leak the array and everything in it, because it doesn't release the array.
Are you running with the garbage collector turned on?
Is list an instance variable or static variable, or is it a local variable?
I figured it out, thanks for all your help, but the problem was outside of the code I posted here. I was not retaining the NSDate I created in my init method. Unfortunatly the crash didn't occur until after I had created the two new NSDate objects, so I was totally barking up the wrong tree.

Resources