Cocoa Threadsafe Mutable Collection Access - objective-c

I'm creating a KVC/KVO-compliant mutable array on one of my objects the recommended way:
#interface Factory {
NSMutableArray *widgets;
}
- (NSArray *)widgets;
- (void)insertObject:(id)obj inWidgetsAtIndex:(NSUInteger)idx;
- (void)removeObjectFromWidgetsAtIndex:(NSUInteger)idx;
#end
Clearly this is a tricky thread-safety issue. In the insert and remove methods I'm locking around array access to prevent concurrent modification, as recommended.
My question is, what is the proper way to implement the widgets accessor? Here's my implementation:
- (NSArray *)widgets {
[widgetLock lock];
NSArray *a = [[widgets copy] autorelease];
[widgetLock unlock];
return a;
}
Is it threadsafe?

Your widgets accessor should be fine, although you should be aware that none of the objects in that array are locked. So, you could run into problems trying to concurrently run code like
[[[myFactory widgets] objectAtIndex:7] setName:#"mildred"];
and
[myTextField setStringValue:[[[myFactory widgets] objectAtIndex:7] name]]; // mildred? or something else?
Since the objects in your array are not locked, you could run into race conditions or readers/writers-type problems. Isn't multithreading a joy?
On a different note, for KVC-compliance, I'd advise implementing objectInWidgetsAtIndex: and countOfWidgets instead of a widgets accessor. Remember, KVC models relationships, not array properties. So you would call something like [myFactory mutableArrayValueForKey:#"widgets"] to get an array representing the widgets property.

Rather than creating your own lock, you could also use the locking built into the language:
i.e
- (NSArray *)widgets {
#synchronized(widgets)
{
NSArray *a = [[widgets copy] autorelease];
return a;
}
}
and use similar locking in all other methods that access widgets. (The parameter widgets passed into #synchronized refers to the instance variable, not the method.)
alex's comment about access to contained objects still apply.

You will need locking on all reading and writing methods. If your insert and remove are also locking (like you said) then the accessor method should be fine like that.

Related

Objective C Convenience Method Use

I am tring to understand convenience methods.
IF I have a sqlite database containing store details and am returning these store details in a FMResultSet. I am thinking that to create an array of these store details as Store objects, that the best way would be create an object of type Store in one go in a convenience method and add to array.
The Class I have created is as below with convenience method
#interface StoreDetails : NSObject
#property (nonatomic, strong) NSString *storeName;
etc etc etc
+ (instancetype)storeWithStoreName:(NSString *)storeName
TelephoneNumber:(NSString *)
telephoneNumber: etc .......
My ResultSet loop would be as below?
NSMutableArray *Stores = [[NSMutableArray alloc] init];
while ([rs next]) {
Store *store =
[Store storeDetailsWithStoreName:[rs stringForColumn:#"storename"]
telephoneNumber:[rs stringForColumn:#"TelephoneNo"]];
[Stores addObject:store];
}
Is my thinking correct as above is is it better to go as below.
NSMutableArray *Stores = [[NSMutableArray alloc] init];
while ([rs next]) {
Store *store = [Store alloc] init];
store.storeName = [rs stringForColumn:#"storename"];
store.telephoneNumber = [rs stringForColumn:#"TelephoneNo"];
[Stores addObject:store];
}
All I am trying trying to understand is why you would use one over the other in noob speak, thankyou.
I think you have a good approach: initializing your Store object in a method of the Store class.
The storeDetailsWithStoreName:... method you have defined is a good example of what Apple calls a factory method (assuming you aren't doing anything weird in its implementation). It's a quite common pattern; Foundation has all sorts of examples: arrayWithCapacity:, numberWithInt:, etc.
With ARC, the simplest examples of these factory methods are nearly identical to a corresponding alloc/init expression, since the developer no longer has to think about autoreleasing objects. But there are still plenty of uses for factory methods, e.g. special instantiation patterns such as singleton or flyweight, including a small amount of common conversion or formatting code for convenience, implementing class clusters, etc. And there's the simple convenience of not having an extra set of brackets and less indentation.
The instancetype keyword is a good choice. This allows you to send the same message to a subclass of Store, with the expectation that the method will instantiate an object of the subclass using the same init method, like this:
+ (instancetype)storeWithStoreName:(NSString *)storeName
telephoneNumber:(NSString *)
...
{
return [[self alloc] initWithStoreName:...];
}
In the code above, as it's a class method, the self in [self alloc] is the Class object (either Store or a subclass of Store) rather than a specific instance of Store. This is what allows creating an instance of the correct class at runtime, depending on whether you call [Store storeWithStoreName:...] or [MoreSpecificStoreSubType storeWithStoreName:...].
The alternative to a factory method, or compliment to it really, is to declare a custom init method in your Store class:
- (id)initWithStoreName:(NSString *)storeName
telephoneNumber:(NSString *)telephoneNumber ...
…and use that directly inside your loop, instead of a factory method. Again, with ARC, not much of a difference between the two unless there's extra work you want to do in the factory method. You can have multiple variants of the init method; the standard practice is for all of them to call the most detailed init method, which is called the designated initializer.
I would recommend taking the time to read the Apple documentation pages on standards for class design (I linked to some of these pages above). Since there are a lot of this is based more on convention rather than language design restrictions, it's important to know all about the patterns and best practices for good design and proper behavior of special methods.

How to replicate NSArray memory semantics in a subclass

Question
In my ARC project I have a class that manages objects, called LazyMutableArray. Some of the objects are actually nil, but users of my collection will never know about this; therefore I made it a subclass of NSMutableArray, and it tries to do "the same thing". In particular, objects are retained when added.
Now let's take a look at a memory behavior of other methods. It turns out that the NSArray destruction methods are documented by Apple to be an exception to this rule, in that they release, not autoreleased object.
There is some debate as to whether the combination of addObject: + objectAtIndex: + array destruction is documented by Apple to be never autoreleasing or simply happens to be in the examples I tested and in the example Apple includes.
How can I create in my subclass a method with exact same memory semantics?
Last update
After some thought, I've decided implementation based on NSMutableArray is more appropriate in this case compared to NSPointerArray. The new class, I should note, has the same retain/autorelease pair as the previous implementation.
Thanks to Rob Napier I see that no modification of my objectAtIndex: method would change this behavior, which answers my original question about this method.
On a practical level, several people said that any method can tackle an extra retain/autorelease pair for no reason; it's not reasonable to expect otherwise and not reasonable to try to find out which methods do this and which do not. It's been therefore a great learning opportunity for me on several levels.
Code (based on NSMutableArray) is available at GitHub: implementation, header, test (that's -testLazyMutableMemorySemantics).
Thank you all for participating.
Why I try to subclass NSMutableArray:
Subclassing foundation objects, I agree, is not always an appropriate solution. In tho case I have objects (in fact, OData resources), most of which have subobjects. The most natural class for an array of subobjects is obviously NSArray. Using a different class doesn't seem to make sense to me.
But for an OData collection this "array of sub objects", while, being an NSArray, must have a different implementation. Specifically, for a collection of 1000 elements, servers are encouraged to return collection in batches of (say)20, instead of all at once. If there is another pattern appropriate in this case, I'm all ears.
Some more detail in how I found this
I unit test the hell out of this collection, and values can be put into array, read from the array, and so forth. So far, so good. However, I realized that returning the object increases its retain count.
How do I see it? Suppose I insert two objects into lazy array lazy, one held weakly, one held strongly (*see the code *). Then retain count of weakSingleton is, as expected, 1. But now I read element:
XCTAssertEqual(weakSingleton, lazy[0], #"Correct element storage"); // line B
And in the debugger I see the retain count go up to 2. Of course, -retainCount may give me wrong information, so let's try to destroy the reference in array by
lazy[0] = nil; // yep, does the right thing
XCTAssertNil(weakSingleton, #"Dropped by lazy array"); // line C <-- FAIL
indeed, we see that weakSingleton is not released.
By now you probably guess that it's not just a retain, it's an autoreleased retain — putting an #autorelease around line B releases the weakSingleton. The exact source of this pair is not obvious, but seems to come from NSPointerArray -addPointer: (and unfortunately not from ARC's [[object retain] autorelease]). However, I don't want to return an autoreleased object and make method semantics different from its superclass!
After all, the method I'm overriding, NSMutableArray -objectAtIndex:`, doesn't do that; the object it returns will dealloc immediately if an array is released, as noted in the Apple's example. That's what I want: modify the method around line A so that the object it returns does not have an extra retain/autorelease pair. I'm not sure the compiler should even let me do it :)
Note 1 I could turn off ARC for a single file, but this would be my first non-ARC Objective-C code. And in any case the behavior may not some from ARC.
Note 2 What the fuss? Well, in this case I could change my unit tests, but still, the fact is that by adding or deleting line B, I'm changing the result of unit test at line C.
In other words, the described behavior of my method [LazyMutableArray -objectAtIndex] is essentially that by reading an object at index 0, I'm actually changing the retain count of this object, which means I could encounter unexpected bugs.
Note 3 Of course, if nothing is to be done about this, I'll document this behavior and move on; perhaps, this indeed should be considered an implementation detail, not to be included into tests.
Relevant methods from implementation
#implementation LazyMutableArray {
NSPointerArray *_objects;
// Created lazily, only on -setCount:, insert/add object.
}
- (id)objectAtIndex:(NSUInteger)index {
#synchronized(self) {
if (index >= self.count) {
return nil;
}
__weak id object = [_objects pointerAtIndex:index];
if (object) {
return object;
}
}
// otherwise do something else to compute a return value
// but this branch is never called in this test
[self.delegate array:self missingObjectAtIndex:index];
#synchronized(self) {
if (index >= self.count) {
return nil;
}
__weak id object = [_objects pointerAtIndex:index];
if (object) {
return object;
}
}
#throw([NSException exceptionWithName:NSObjectNotAvailableException
reason:#"Delegate was not able to provide a non-nil element to a lazy array"
userInfo:nil]);
}
- (void)createObjects {
if (!_objects) {
_objects = [NSPointerArray strongObjectsPointerArray];
}
}
- (void)addObject:(id)anObject {
[self createObjects];
[_objects addPointer:(__bridge void*)anObject];
}
The complete test code:
// Insert two objects into lazy array, one held weakly, one held strongly.
NSMutableArray * lazy = [LazyMutableArray new];
id singleton = [NSMutableArray new];
[lazy addObject:singleton];
__weak id weakSingleton = singleton;
singleton = [NSMutableDictionary new];
[lazy addObject:singleton];
XCTAssertNotNil(weakSingleton, #"Held by lazy array");
XCTAssertTrue(lazy.count == 2, #"Cleaning and adding objects");
// #autoreleasepool {
XCTAssertEqual(weakSingleton, lazy[0], #"Correct element storage");
XCTAssertEqual(singleton, lazy[1], #"Correct element storage");
// }
lazy = nil;
XCTAssertNotNil(singleton, #"Not dropped by lazy array");
XCTAssertNil(weakSingleton, #"Dropped by lazy array");
The last line fails, but it succeeds if I change first line to lazy = [NSMutableArray new] or if I uncomment #autoreleasepool.
First, I would not make this subclass. This is exactly what NSPointerArray is for. Wrapping that into an NSArray obscures important details that this approach can break. For example, what is the correct behavior for [NSArray arrayWithArray:lazyMutableArray] if lazyMutableArray includes NULLs? Algorithms that assume that NSArray can never include NULL need to be wary of the fact that this one can. It's true that you can get similar issues treating a non-retaining CFArray as an NSArray; I speak from experience that this is exactly why this kind of subclass can be very dangerous (and why I stopped doing that years ago). Don't create a subclass that cannot be used in every case that its superclass can be used (LSP).
If you have a collection with new semantics, I would subclass it from NSObject, and have it conform to <NSFastEnumeration>. See how NSPointerArray is not a subclass of NSArray. This was not an accident. Faced with the same problem, note the direction Apple chose.
By now you probably guess that it's not just a retain, it's an autoreleased retain — putting an #autorelease around line B releases the weakSingleton. This seems to be because line A under ARC translates to [[object retain] autorelease]. However, I don't want to return an autoreleased object and make caller remember this!
The caller should never assume anything else. The caller is never free to assume that a method does not add balanced autoreleases. If a caller wants the autorelease pool to drain, that is their responsibility.
All that said, there is some benefit to avoiding an extra autorelease if it's not required, and it's an interesting learning opportunity.
I would start by reducing this code to the simplest form, without your subclass at all. Just explore how NSPointerArray works:
__weak id weakobject;
#autoreleasepool
{
NSPointerArray *parray = [NSPointerArray strongObjectsPointerArray];
{
id object = [NSObject new];
[parray addPointer:(__bridge void*)object];
weakobject = object;
}
parray = nil;
}
NSAssert(!weakobject, #"weakobject still exists");
My structure here (such as the extra nesting block) is designed to try to avoid accidentally creating strong references I don't mean to make.
In my experiments, this fails without the autoreleasepool and succeeds with it. That indicates that the extra retain/autorelease is being added around or by the call to addPointer:, not by ARC modifying your interface.
If you're not using this implementation for addObject:, I'd be interested in digging deeper. It is an interesting question, even if I don't believe you should be subclassing this way.
I'm going to elaborate on why I said this "looks a lot like a homework assignment." This will likely earn me many down votes, but it will also server as a good learning case for others who later find this question.
Subclassing NSMutableArray not a goal of a program. It is a means to achieve something else. If I were to venture a guess, I expect you were trying to create an array that lazily creates the object when they are accessed. There are better ways to do this without dealing with memory management yourself.
Here's an example of how I would implement a lazy loading array.
#interface LazyMutableArray : NSMutableArray
- (id)initWithCreator:(id(^)(int))creator;
#end
#interface LazyMutableArray ( )
#property (nonatomic, copy) id (^creator)(int);
#property (nonatomic, assign) NSUInteger highestSet;
#end
#implementation LazyMutableArray
- (id)initWithCreator:(id(^)(int))creator
{
self = [super init];
if (self) {
self.highestSet = NSNotFound;
self.creator = creator;
}
return self;
}
- (id)objectAtIndex:(NSUInteger)index
{
id obj = nil;
if ((index < self.highestSet) && (self.highestSet != NSNotFound)) {
obj = [super objectAtIndex:index];
if ([obj isKindOfClass:[NSNull class]]) {
obj = self.creator(index);
[super replaceObjectAtIndex:index withObject:obj];
}
} else {
if (self.highestSet == NSNotFound) {
self.highestSet = 0;
}
while (self.highestSet < index) {
[super add:[NSNull null]];
self.highestSet += 1;
}
obj = self.creator(index);
[super add:obj];
self.highestSet += 1;
}
return obj;
}
Fair Warning: I'm not compiling or syntax checking any of this code. It probably has a few bugs in it, but it should generally work. Additionally, this implementation is missing an implementation of add:, count, removeObjectAtIndex:, insertObject:atIndex:, and possibly replaceObjectAtIndex:withObject:. What I show here is just to get you started.

How to check assignment since addObject doesn't access setter?

I just noticed that calling addObject: on an NSMutableArray doesn't access that array's setter.
E.g., for NSMutableArray self.myArray, [self.myArray addObject:object] does not use [self setMyArray:array] to add the object.
Previously I have been using custom setters and getter to check assignment before assigning; e.g., if I wanted an array that only accepted objects of class MyClass, I would do the following:
- (void)setMyArray:(NSMutableArray *)myArray
{
for (id object in myArray)
{
if (![object isKindOfClass:[MyClass class]]) return;
}
_myArray = myArray;
}
- (NSMutableArray *)myArray
{
if (!_myArray) _myArray = [[NSMutableArray alloc] init];
_myArray = myArray;
}
How do I go about achieving this same functionality when changing the array via addObject:, removeObject:, and other similar functions that may circumvent the setter?
Generally this kind of problem is the reason why NSMutableArray is usually avoided in preference of NSArray.
This is the simple solution, use NSArray instead of NSMutableArray:
self.myArray = [self.myArray arrayByAddingObject:foo];
However, if the array is really big that will cause performance issues. Then you've got two options:
you can have your own addObjectToMyArray: method in your class and always use that
you can create an NSArrayController and use that to access your array. It will implement key value observing and bindings and all of that stuff.
NSMutableArray is designed to perform addObject: with as few CPU instructions as possible and therefore does not proved any way for external code to be notified that the object was added. You have to have some other class wrapped around it.
Do not try to subclass NSMutableArray, because it is a "class cluster" making subclasses extremely complicated.
If what you wish to do is ensure objects in the array are of a particular class then this answer to the question "NSMutableArray - force the array to hold specific object type only" provides code to do exactly that.
If you wish to do other checks on assignment then you can use the code in that answer as a starting point.

Is it best to return NSArray or void and update self property?

I am working on a delegate class that controls several views, and find myself switching between updating properties in the delegate and returning values from methods. What is the proper way to do this?
-(NSArray)blah{
return myarray;
}
or
-(void)blah{
[self myarray:value]
}
--------------- Clarification of question below
if I have a helper method that converts an NSArray into a NSDictionary
should I call my helper method and expect a return of NSDictionary, or should I update a variable in memory and return void.
There's a case for each approach, depending on what you are really doing. The two choices are:
It is truly a helper method, that has use in many places in your application.
It is specific to a single class and the dictionary is a member of that class.
OPTION 1) If it is truly a helper method, I believe that you should return the NSDictionary from the method. I'm assuming it is newly allocated within that method.
In other words, prefer:
+ (NSDictionary *) dictFromArray:(NSArray *);
If it has utility outside of a single class, you could put it in a sensible class that collects related utility methods.
The alternative approach of passing in an empty dictionary to be filled is practiced in C because it creates symmetry around allocating and freeing and makes it clear who owns the memory.
In Objective-C, reference counting takes care of that, so you can avoid the extra code of allocating empty objects just to call the method.
For example:
NSMutableDictionary *myDict = [[NSMutableDictionary alloc] init];
dictFromArray(myArray, myDict);
When it comes to knowing who owns the object, you should stick to Objective-C conventions, where:
+ (NSDictionary *) dictFromArray:(NSArray *)array
returns an autorelease object, so the caller knows they need to retain it if they want to hold a reference.
OPTION 2) If the functionality is specific to a single class and that class has the dictionary as a member, then I would pass in the array, update the dictionary member variable using the array contents, and return void.
Something like:
- (void) setBlahFromArray:(NSArray *)array
The question is confusing as stated. If they are properties then you have accessor methods that usually include something like:
-(void) setMyValue: (NSString*) inNewValue;
-(NSString*) myValue;
but it seems like you are probably asking something else since these can be dynamically synthesized for you by the compiler... So try rephrasing the question and we'll try again to help.

Subclassing in Objective-C

I'm a bit new to Objective-C, and I've been trying to do something that apparently isn't allowed, even though it's common practice in other languages (I think).
As a specific example, I want to subclass NSMutableArray to make a SortedMutableArray that always maintains itself in a sorted state. So I subclassed NSMutableArray in the usual manner, adding a NSComparator property that determines the sort order. I overrode the addObject: method to insert objects in a sorted manner:
- (void) addObject:(id)anObject {
for (int i = 0; i < [self count]; ++i) {
NSComparisonResult result = (NSComparisonResult)self.comparator([self objectAtIndex:i], anObject);
if (result == NSOrderedDescending || result == NSOrderedSame) {
[super insertObject:anObject atIndex:i];
break;
}
else {
if (result != NSOrderedAscending) {
[NSException raise:#"InvalidBlockException" format:#"Block must return one of NSOrderedDescending, NSOrderedAscending, or NSOrderedSame"];
}
}
}
}
and everything compiles great. But when I run the program, I get an error indicating that insertObject:atIndex: is now abstract and needs to be implemented. Reading the documentation, it lists several methods that must be implemented in any subclass of NSMutableArray, one of which is indeed insertObject:atIndex:. But I don't need to change the functionality of insertObject:atIndex:; I want it to word exactly as it does in NSMutableArray. Is there a way that I can do this (in general, too, not just for this specific problem)? Why must certain methods be implemented in subclasses like this? Doesn't that kind of defeat one of the purposes of inheritance, code reuse? I've never seen anything like this in other languages, where a method is concrete in a superclass but becomes abstract when it is subclassed. Does this pattern/concept have a name?
Thanks in advance for any help, and I'm sorry if I'm duplicating another question, but I didn't know what to search for other than "subclass" in the objective-c tag, which gave too many results to find what I was looking for.
Bad idea. NSArray is actually a class cluster (which is our word for [essentially] an abstract factory). This means that when you alloc/init an NSArray, you don't actually get an NSArray back. You get (usually) an NSCFArray, which is a private subclass.
NSMutableArray is the same deal (it's abstract). When you alloc/init an NSMutableArray, you get an NSCFArray back that has a little internal mutable bit flipped.
The upshot of this is that subclass a class cluster is generally discouraged, because it's a bit more complex than just creating a normal subclass.
What I would recommend is to instead check out the CHDataStructures framework, which has a whole bunch of data structures that do what you're looking for already.
See Dave DeLong's post about why this is a not a good idea.
If you really want to do something like this, you could try, uhmm, "fake-subclassing" it.
in the .h file,
...
NSMutableArray *mutableArray;
...
#property (nonatomic, retain) NSMutableArray *mutableArray;
...
- (void) addObject:(id)anObject;
in the .m file,
...
#synthesize mutableArray;
...
- (void) addObject:(id)anObject {
[mutableArray addObject:id];
[mutableArray sortUsingSelector:#selector(yourSortingSelector);
}
- (NSMutableArray)mutableArray {
return mutableArray;
}
...
Which works and everything. My colleague did a similar class to this before (we were objective-c noobs at the time, about 2-3 weeks into learning how to code).
What I would recommend, however, is to use a Key-Value Observing approach if you can. Try to listen in whenever an element is added, and sort your array when you get the notification. I haven't done this to an NSMutableArray before though, so I don't know how this will work or if it even will.
My 2 cents, hope it helps. Happy holidays! ^_^
You shouldn't be subclassing NSMutableArray, look up categories. It provides a way to add newer methods to classes
apple's link to categories