Specific Getting index of NSMutableArray Problem - objective-c

I have a bit of a problem in my code, and i'm beginning to wonder if it's a design issue..
I'm treating my appDelegate class as the primary model for my application. With the appDel class, I have a viewcontroller. In my appdelegate class I store an NSMutableArray called blocks which has all of my block object models. Similarly, in my viewcontroller I have an identical NSMutableArray called blockViews which stores all of my block object views. The way I update the view after receiving notifications from the model is through KVO. In my viewcontroller, I observe each location property of each block in my blocks array (in the app delegate), and update the corresponding blockView in blockViews.
I also have it set up so that whenever I add an object to my blocks array in the appDel, it adds an object to the end of the blockViews' array. Now, my problem arises when I try to remove an object from my blocks array (in the appDel class). I will not always be removing the last object, and so I am stuck as to how to get the actual index of the object I am trying to remove so that I can remove the corresponding index in my blockViews NSMutableArray.
In my observeValueForKeyPath method, the object being passed is the appDelegate class because I am observing the entire blocks array from my viewcontroller (I implemented the Indexed Array Accessors to allow for KVO notifications to occur), and because of this the object being passed into observeValueForKeyPath is in fact a reference to my appDelegateClass (which makes sense).
But, from this, I cannot obtain the index of which object was removed from the blocks array. Does anybody have any suggestions as to how I could alter this to provide an index, or a way to get the correct index?
Is there any way to observe an array for additions or removals, AND have the object being passed into my observeValueForKeyPath method be the block that was added/removed itself, instead of the appdelegate class?

Can't you use indexOfObject... (several variations) to get the index, and then remove it in both arrays? (You realize that NSMutableArray implements all the methods of NSArray, right?)

Related

NSMutableArray with tableview source data modified in multiple threads, how to avoid blocking while configuring the cell

I have a NSMutaleArray that contains instances of class X. The tableView cell at row i is populated using contents of array at index i.
The contents of the array are created based on incoming JSON data from the network. So, I have a helper function that converts JSON data into these objects and stores them in the array. The object may be modified after storing in the array (for instance image belonging to cell gets downloaded and file pointer is added to the object).
Currently, I am making the reads and writes thread safe putting them inside dispatch_sync & dispatch_barrier_async. Some issues I see
To create the tableview cell I need to do a read. This is also going through the dispatch_sync. Hence, it looks like there is chance of it getting blocked because data for a non-visible but close enough cell is being updated. Any best practices to avoid this?
Is there some smart way for the block submitted through dispatch_sync and disaptch_barrier_sync to only wait if another block is either modifying, removing the same index of the NSMUtableArray or value associated withs are key of NSMUtableDictionary?
To make the code more readable, I am thinking of sub-classing NSMutableArray and creating a THreadSafeMutableArray class that over-rides the objectForIndex and subscript methods. Any issues with this approach?
Your NSMutableArray should be an atomic property (the default value is this) maybe you changed to nonatomic in the declaration.
Look the documentation: https://developer.apple.com/library/mac/documentation/Cocoa/Conceptual/ProgrammingWithObjectiveC/EncapsulatingData/EncapsulatingData.html
Apple documentation:
This means that the synthesized accessors ensure that a value is always fully retrieved by the getter method or fully set via the setter method, even if the accessors are called simultaneously from different threads.
#interface XYZObject : NSObject
#property NSObject *implicitAtomicObject; // atomic by default
#property (atomic) NSObject *explicitAtomicObject; // explicitly marked atomic
#end

Add Custom View when Custom Model is Added

My appDelegate class contains an NSMutableArray called blocks, which is an array of custom block objects.
My viewcontroller class has another NSMutableArray called blockViews, which is an array of custom blockView objects. In its init method, it sets it backgroundcolor to a color passed in the parameter, and does some fancy stuff with the border.
Whenever an object is added to my blocks array, I would like to also add a corresponding object to my blockViews array in my viewcontroller, which shares the same location as the location passed to the block object in the blocks array, and adds itself as a subview to the viewcontroller.view.
I would preferably like to use KVO to check whenever an object is added to the blocks array, and then add an object to the blockViews.
I'm relatively new to objective-c programming, but how might someone accomplish this?
Peter Hosey's answer to another question will tell you what you need to know about KVO with NSMutableArray.
In your case, the thing observing the NSMutableArray should be your view controller.

Share NSArray instance to KVO objects

I have a controller class that store a list of contact and I need to share this list to objects that will implement KVO on such array.
The most obvious solution is to use a NSArray instead of NSMutableArray, in order that everyone can use the same instance variable of the controller and it's not possible modify the content of the array.
Now, let's image that this list can change every 3 minutes and only the controller can update the content of the array.
If I dealloc and re-init the contact list array, all my KVO objects will lost the reference to my array.
Finally:
NSArray PRO: No one can alter the content of the array
NSArray CON: The controller can not modify the array without a dealloc, so other objects lost the reference.
NSMutableArray PRO: Controller can modify array content, all the object can easily share the same reference of the array
NSMutableArray CON: Everyone can modify the array.
Any suggestion?
NSArray in my opinion, given that it isn't being updated very often.
The object that owns and modifies the array exposes it through a property of type NSArray*. The observers observe this property. Whenever the object that owns the array recreates it, it sets the property to the new NSArray which then triggers KVO on all of the observers.
Alternatively, you can implement the indexed accessor patterns for the property.

Adding array from one view to another and retaining values

I have four views, with four arrays. As soon as I navigate from one view, I add that particular array to my master array.
Initially this master array has nothing, and is allocated when the app runs using 'init' method. It does not have a view and it is an array from a subclass of NSObject.
Finally the master array should consist of {viewarray1, viewarray2, viewarray3, viewarray4}.
Each array is added to the master array when navigating to the next view.
So is there anything wrong in my implementation ? Is it okay to allocate masterArray in the init method? Each time I add an object to masterArray, I NSLog it and it displays (null)
How can I have the master array retain values for the whole app??
Some Information on the Code:
I initialize my master array in another class, in the -(init) method
masterArray = [[NSMutableArray alloc] init ];
While adding an object to MasterArray from another view, I reference that class, and I create an object for the class, and add it as a property and synthesize it. I then use
[self.thatClassObject.masterArray addObject:self.viewArray1];
There are two ways you could go about initializing it that I can think of offhand. First, you could alloc/init the array in the app delegate. This will ensure it's created before the rest of the views get a chance to add to it.
EDIT: There's only really one way I can think to do this as Josh Caswell pointed out a good fact that class initializations won't work for this situation. You're best off calling alloc/init for the array either in the app delegate or whichever view is made key window first. You'll have to reference it to the other classes from there

How to add alive object to NSMutableArray and remove them when they're released?

I have class Item and class List (which has an NSMutableArray).
Every time class Item is instantiated (and destroyed) it posts a notification, which is listened-to by class List. When class List receives the notification is adds the instance of class Item to its list.
I'm trying to have class Item also post a notification that its about to be dealloc'd. The problem is that class List's NSMutableArray retains the instance of class Item.
What's the most appropriate means of handling this situation? If I decrement the count when adding it to List's array, then an exception will be thrown when class List attempts to call removeObject (since it'll try to dealloc the object.)
Basically, I want a "monitor" class List that contains a list of all "live" instances of Item. But, I also need the ability to release/dealloc the instances and have them report they're being dealloc'd so List can remove them from its NSMutableArray.
Thanks for your help.
If I understand correctly, you want an array that maintains weak references to its items, as opposed to strong references?
I don't know of a way to do this with anything "built-in" in Cocoa. The only way I'd know of to do this is to make the array yourself, and have the storage be __weak id[]. That would automatically zero-out the place in the array when the object deallocates. If you're under the retain-release model, you could use something like MAZeroingWeakRef to get the same behavior.
This is definitely an interesting question, and I don't know of an easier answer. I'd love to be proven wrong!
Ha, I love being wrong!
There's a class called NSPointerArray that looks like it can do what you're looking for. However, it's only available on the Mac, and it only auto-zeros when you're using garbage collection.
I'll keep thinking about this. This is an interesting problem! :)
So I kept thinking about this, and came up with a solution. It uses two unconventional things:
A subclass of NSMutableArray (egads!)
Using an associated object to determine object deallocation
For the first bit, I had to to subclass NSMutableArray so that I could inject some custom logic into addObject: (and related methods). I didn't want to do this via swizzling, since NSArray and friends are a class cluster, and swizzling into/out of clusters is fraught with peril. So, a subclass. This is fine, but we're going to lose some of the awesome features we get from "pure" NSArray instances, like how they do weird things when they get big. Oh well, such is life.
As for the second bit, I needed a way for any arbitrary object to notify that it is about to or just finished deallocating. I thought of dynamically subclassing the object's class, injecting my own dealloc/finalize method, calling super, and then smashing the isa of the object, but that just seemed a little too crazy.
So, I decided to take advantage of a fun little thing called associated objects. These are to ivars what categories are to classes: they allow you to dynamically add and remove pseudo-instance variables at runtime. They also have the awesome side effect of getting automatically cleaned up with the object deallocates. So what I did is just created a little throw away object that posts a notification when it is deallocated, and then attached it to the regular object. That way when the regular object is deallocated, the throw away object will be as well, resulting in a notification being posted, which I then listen for in the NSMutableArray subclass. The notification contains a (stale) pointer to the object that is in the process of getting destroyed, but since I only care about the pointer and not the object, that's OK.
The upshot of all of this is that you can do:
DDAutozeroingArray *array = [DDAutozeroingArray array];
NSObject *o = [[NSObject alloc] init];
[array addObject:o];
NSLog(#"%ld", [array count]); //logs "1"
[o release];
NSLog(#"%ld", [array count]); //logs "0"
The source is on github, and it should (theoretically) work just as well on iOS as Mac OS X (regardless of GC mode): https://github.com/davedelong/Demos
Cheers!
... and I just thought of a way to do this without a custom subclass, but I'm tired and will post the updated answer tomorrow.
the next morning...
I've just updated the project on Github with an NSMutableArray category that allows you to create a true NSMutableArray that auto-zeroes its objects as they're deallocated. The trick was to create a CFMutableArrayRef with a custom retain callback that sets up the proper observation, and then just cast that CFMutableArrayRef to an NSMutableArray and use that (ah, the magic of Toll-Free Bridging).
This means you can now do:
NSMutableArray *array = [NSMutableArray autozeroingArray];
I added a typedef to define these as NSAutozeroingMutableArray, just to make it explicitly clear that while this is an NSMutableArray, it doesn't retain its objects like a normal NSMutableArray. However, since it's just a typedef and not a subclass, you can use them interchangeably.
I haven’t tested this, so comments are welcome.
You could use an NSPointerArray for the list (in a retain property):
self.array = [NSPointerArray pointerArrayWithWeakObjects];
When an Item object is created, it would post a notification that’s listened by your List class. Upon receiving the notification, List adds the object to the pointer array:
[array addPointer:pointerToTheObject];
In this setting, the pointer array doesn’t keep a strong reference to its elements — in particular, it doesn’t retain them. This applies to both garbage-collected and non-garbage-collected builds.
In a garbage-collected build, if an element is garbage collected then the garbage collector automatically assigns NULL to the position in the array where the object was stored.
In a non-garbage-collected build, you’ll need to manually remove the element or assign NULL to the position in the array where it was stored. You can do this by overriding -[Item dealloc] and posting a notification that the object is being deallocated. Your List class, upon receiving the notification, would act upon it.
Note that, since objects are not owned by the pointer array, you must keep a strong reference to (or retain) them if you want to keep them alive.