I have to maintain a code of somebody. The code opens a thread. The thread worker function in iOS (and any other language I know of) accepts only one parameter. In order to overcome this, the code creates an array, adds all the parameters into an array and passes it into the thread. Here is the code.
NSArray* params = [[NSArray alloc] initWithObjects: mainView, actionFlag, nil];
[self performSelectorOnMainThread:#selector(updateWorker:) withObject:params waitUntilDone:NO];
And the function is called this way
-(void)updateWorker:(NSArray*)params
{
UIView* view = [params objectAtIndex:0];
bool actionFlag = ((NSNumber*)[params objectAtIndex:1]).boolValue;
/* do stuff with view and actionFlag */
}
I have a gut feeling that this is very wrong at so many levels but cannot built a valid argument for this case.
What are the drawbacks of passing number of arguments as an array?
Actually what you are doing is technically correct (but I do understand why it feels wrong).
If you want to feel better, what I would do in this case is instantiate (create) a "NSDictionary" object and then set the objects / values to useful keys and in your "updateWorker" method, fetch the objects via "objectForKey:".
Doing it this way will be easier for you (or somebody else) to maintain in the future, as you won't have to poke around to see what goes in array position 1, array position 2, etc.
Most of them are future updates,
Some cases (not so rare) may happen:
Addition of new parameters to the array
changing the order of elements in the array
removing elements in the array
problems when releasing and retaining elements in the array (not ARC)
One point to note here, is that all of these cases will be hard to debug, since you will be moving from one thread to the other
Related
Ive tried digging around in old posts, but they were kind of obsolete and years old, so I was concerned things might have changed due to ARC being introduced etc.
Mainly I was looking at some fairly new code that used alloc on an array, which was declared as a property in the header. I was thinking, I don't normally do this and everything is working smoothly. But then came to my mind UIButton and UILabel for example, which has to have alloc invoked, or they won't be added to the view when you want that. Are there any rough guidelines for when its actually needed. I would think any object needs this, but the array vs. button/label thing as I just described made me wonder what is the reasoning behind this.
Thanks in advance
This is 100% dependent on the actual objects being used from the framework. The really great news, though, is that Apple is extremely consistent. If you send a message that contains an "Alloc" in it anywhere, you are responsible for making sure that it has been released.
Here's a super document on it from Apple.
You use alloc always if you create the object on your own.
Which means that sending alloc is normally followed by an init method.
It might sometimes look like it's not always the case, as many classes have convenient constructors that return an already allocated and initialized object to you.
But there is still alloc and init called to create the object.
It's just done for you by the system.
But the difference between convenient constructors and manually creating objects isn't new to ARC, it has always been around.
Example for creating an NSArray on your own:
[[NSArray alloc]initWithObjects:#"Test", nil];
and as NSArray has an convenient constructor here the example for that:
[NSArray arrayWithObjects:#"Test", nil];
If you use ARC, there is no real difference.
Without ARC, the object returned by the convenient constructor would still be autoreleased, while the manually allocated object has to be released by you at a later point (or you have to add an autorelease after the init).
So the main difference is the owner ship:
In the manually created example the object belongs to you, so you are responsible to clean up after you don't need it anymore.
If something is declared in .xib then it is automatically allocated for you. Just use it. While If you are creating a view in code u must alloc it first. And if you have a property NSArray/NSMutableArray etc, u might be doing one of the following:
_array = [NSArray new];
_array = [[NSArray alloc] init];
_array = [NSArray arrayWithObjects: values count:2];
_array = # ["ABC", "xyz"];
etc,
so you are actually allocating it if you are using any of these methods.
I do not really understand, what
they won't be added to the view when you want that.
means, but here is the story:
Every object is allocated using +alloc. To be honest, it is +allocWithZone:, but this does not have any meaning at this place.
The very first message you have to send to the newly created instance object (remember: you sent +alloc to the class object) is an initialization message, something like init…. To put this together you will find code as:
… [[TheClass alloc] init…] …;
Because it is boring typing there are new allocators. They put this messages into one:
… [TheClass new…] …;
(This has some advantages for the class implementor, too, but this is transparent to you. Think of it as sending +alloc, -init….)
In earlier times it has been a good idea to send an autorelease message to it as the next step for some reasons:
… [[[TheClass alloc] init…] autorelease] …;
This has been put together to convenience allocators:
… [TheClass theClass…] …
This is what you find most of the time when reading old code. Using ARC you do not need convenience allocators anymore: There is no autorelease. So there is no reason for convenience allocators anymore. But we had MRR for years and there are still many convenience allocators. (Now called factory methods, but CA's are only a subset of these. A subset you do not have to care about. It's all gone with ARC.) Because there are that many CA's, one still uses them. (And there is a performance issue with them. In nowadays I only write new allocators, which has the advantages of a CA, but not the disadvantage of autorelease.)
To make a long story short: You simply do not see sometimes that +alloc is used.
I'm facing "Collection was mutated while being enumerated" crash in dispatch_async method. This is the code:
- (void) addCutObjectFromObject: (Object *) object {
dispatch_async(self.objectsQueue, ^{
ObjectCut *objectCut = [[[ObjectCut alloc] init] autorelease];
objectCut.objectId = object.uid;
objectCut.objectName = object.internal.name;
#synchronized(self.shownChannelsArray) {
if (![self.objectsArray containsObject: objectCut])
{
[self.objectsArray addObject: objectCut];
}
}
});
}
Dispatch_queue is created in the init method like this:
_objectsQueue = dispatch_queue_create("objectsQueue", DISPATCH_QUEUE_CONCURRENT);
dispatch_retain(_objectsQueue);
The code crashes without synchronized block. As far as I know, it should not crash, because there is no loop, and blocks should be added one-by-one waiting for their queue. Can someone explain me, why that is happening?
dispatch_queue_create("objectsQueue", DISPATCH_QUEUE_CONCURRENT) creates a concurrent queue. Arbitrarily many blocks dispatched to that queue may execute simultaneously. It's likely that containsObject: uses enumeration internally to do a linear search. Therefore one block is in the middle of containsObject: while another performs addObject:. NSMutableArrays are, like the other Foundation mutable objects, not guaranteed to be thread safe.
At the very least you want to use DISPATCH_QUEUE_SERIAL. Unless the order is really important to you or your objects don't implement hash, isEqual:, etc, you should probably also just use a set rather than sort of manually recreating one with an array.
Aren't you calling addCutObjectFromObject: from a loop or an enumeration ?
If It is, you may want to check this part.
Ah a tricky one.. from my knowledge (and I may be a bit off, so others, feel free to follow up, but this poor chap doesnt have any responses yet..
so when this executes, the async block will not run right away. It will first be scheduled, I would imagine you are calling this addCutObjectFromObject method more than once. Let's say for example sake that you are calling this method 5 times. Now think about threads. The first call gets scheduled, eventually begins running, while the second call gets scheduled, eventually starts running, etc.. and this is where the problem starts and I believe your culprit is in containsObject and addObject. Under the hood, containsObject is iterating through the array. Since there are more than 1 thread executing, while one thread is iterating the array, another could be calling addObject. Thus generating your crash of 'collection was mutated while being iterating'
Two options for solutions
1) in containsObject, check against a copy of the array rather than the array itself (this is a bad approach because it requires duplicating of the content of the array, BUT it is easy to put in, and for small array sizes, could be a quick fix)
if (![self.objectsArray containsObject: objectCut]) =>
if (![[NSArray arrayWithArray:self.objectsArray] containsObject: objectCut])
Again, this should stop your sporadic crashes, but this is a BAD SOLUTION (because of the memory duplication)
2) create a temporary array to add the objects to, and once all threads are finished, add the contents of the temporary array to self.objectsArray
The error says the reason of crash. It is not allowed to change an array while enumerating.
if (![self.objectsArray containsObject: objectCut])
{
[self.objectsArray addObject: objectCut];
}
In the above code you were enumerating the array an inserting and object. This is where the error will be given. Hope this helps .. :)
Data comes from the server in JSON, which is placed in a NSDictionary. Depending on type of requested data the new class object will be created from this NSDictionary. There're a lot of data comes, so the object holds a reference to NSDictionary and extracts a value only when referring to a particular variable. Something like lazy initialization:
- (NSString *)imgURL {
if (_imgURL == nil) {
_imgURL = [self makeObjForKey:kImageURL];
}
return _imgURL;
}
This significantly increases application speed, but produces other problems:
If a value is absent in NSDictionary, it remains nil. Then for each subsequent call to this variable there occurs search for it in NSDictionary.
When copying the entire instance of the class (NSCopying protocol), all variables are copied, producing convertion from entire NSDictionary.
Solutions:
Put some flag indicating that value has been checked. But then you
have to add additional checks
Only copy NSDictionary for object instance, but then later have to
parse same variables again
Anyway these solutions are not optimal. Maybe somebody faced with a similar problem and can advise other techniques.
NSDictionary lookups are very fast. Unless this is a truly enormous dictionary, I wouldn't worry too much about the lookup. If you have some properties that are checked particularly often, then you could optimize them with a special flag, but I usually wouldn't worry about it.
For copying, my first recommendation is to make this object a value (immutable) object. Initialize it once with JSON and then provide no mutators (that may be what you're doing already). Then copy is trivial; just return self. You don't need to make a real copy, because all copies are interchangeable. One of the great benefits of value objects is how cheap and easy they are to copy.
If you sometimes really need a mutable version, then follow the NSArray/NSMutableArray pattern. Then only the mutable version will have to deal with copies (in which case you should just copy the dictionary; not the cached objects).
EDIT: This is for a static NSMutableDictionary, not a class member. I see a lot of answers thinking it's a class member, sorry about that. Thanks for the quick responses.
I had a working piece of code, but it was used 2x, so I wrote a convenience function:
- (void) initializeDictionary:(NSMutableDictionary*)mutableDict fromPathName:(NSString*)path
{
mutableDict = // get from file, init if not there.
}
Then I noticed nothing was saving. Stepping through the code, the function creates a dictionary, but the "passed in" value is still nil upon returning. This completely blows away my understanding of pointers (don't take this the wrong way, I'm very comfortable). But their purpose, I thought, was to let you "pass the address" so I could hydrate the thing it points to.
since mutableDict is the "value copy", ARC appears to be wiping it out. I'm asking here because
the other questions have the opposite question "Why is this being retained?" and
It doesn't seem right. Your very first tutorial in any pointer language is "so you can mess with the original value". Does Arc really do this? Is there a concept I'm not getting?
And of course, I may be overlooking something simple.
I seem to have solved it by doing the writeback trick I found elsewhere:
- (void) initializeDictionary:(NSMutableDictionary* __strong *)mutableDictionary fromPath:(NSString*)path;
and using the & to call and * deref to change the value. It just seems far less than elegant.
You pass a pointer of NSDictionary. If you change the pointer value of mutableDict (by allocation or assignment) this will NOT be reflected on the variable passed as this function's argument and since mutableDict is locally defined in the function it will be released by ARC automatically. (Do not forget that even for pointers the address is copied when passed to a function).
The reason that your second solution works is because you pass a pointer to a pointer (not sure if strong is needed there). The value of *mutableDict will be reflected outside since you update a value in the address pointed to by mutableDict. This value is the address of your allocated dictionary and since you change it via a pointer it will be reflected outside the function.
To do what you want you use multiple indirection
- (void) initializeDictionary:(NSMutableDictionary**)mutableDict fromPathName:(NSString*)path
{
mutableDict = // get from file, init if not there.
}
Notice the parameter is (NSMutableDictionary **), a pointer to a pointer to an NSMutableDictionary.
To call the method you need to create a pointer and pass it in like this:
NSMutableDictionary *mutableDictionary;
[self initializeDictionary: &mutableDictionary fromPathName:...];
And on return, the mutableDictionary variable will have been initialised by the method.
However, It's probably easier to just return the dictionary from the method rather than doing it this way.
In Objective-C if you define a variable in a method, the variable is visible only in that method.
If you need to save the variable to use it outside, you need to "return" it from your function. What you did wasn't a trick, is another way of returning a variable.
Try with:
- (void)initializeDictionaryFromPath:(NSString*)path {
NSMutableDictionary *mutableDict = // your initialization
return mutableDict;
}
Then you can define your dictionary with this code:
NSMutableDictionary *mutableDict = [self initializeDictionaryFromPath:path];
When it comes to accessing objects from different methods in the same class, from what I understand, these are two ways to do it. Given that I DO want to hold a property pointer to this object, which is the better way to go about this? I've been thinking about this for a while, and wondered if there is a preference consensus.
#1:
NSArray *array = ... // Get array from somewhere
self.myArray = array;
[self doSomethingToMyArray];
This method takes no parameter and accesses the array via its own property via self
- (void)doSomethingToMyArray
{
// Do stuff with/to the array via self.myArray
[self.myArray ...];
}
Vs #2:
NSArray *array = ... // Get array from somewhere
self.myArray = array;
[self doSomething:array];
This method takes an array and accesses the array via its own method parameter
- (void)doSomething:(NSArray *)array
{
// Do stuff with/to the array via method parameter "array"
[array ...];
}
I think it's primarily going to depend on what doSomethingToMyArray does and who calls it.
Fairly obvious comments:
if you want to do that to more than one array, you need to take an argument;
if what you're doing is actually logically more to do with the array than with your class (e.g. you've implemented randomisation of the order of the array) then it'd be better as a category on NSArray rather than being anywhere in that class at all;
if there's any possibility of subclasses wanting to redefine the manner in which the array is obtained then you'll want to invoke the getter somewhere;
similar concerns apply if a subclass or an external actor should be able to intercede anywhere else in the process.
Beyond those concerns there are a bunch of us that just prefer this stuff to be functional anyway — noting that you're doing something to the array, not with the array, in which case you'd tend more towards self.myArray = [self processedFormOf:array] (or self.myArray = [array arrayByDoingSomething]; if the category tip makes sense).
So, ummm, I don't think there's a clear-cut answer.
That depends on what you want to do, just by reading it:
doSomething:array
I would assume the above method takes ANY array and performs an action, whereas:
doSomethingToMyArray
with this method you are describing the intention of doing something to your instance's array. Inside this method (given that you followed Apple good coding practices and you synthesized your property to _myArray) , you could either go with:
[self.myArray message]
or preferably
[_myArray message]
Your second option is sort of silly. If you're storing a pointer in an instance, then it's so that you can use it later (within that instance) without needing to pass it around whenever you call a method.
This is also dependent on whether you're using ARC or not (use ARC if this is a new project). In a non-ARC project, self.myArray = foo; will do a very different thing than myArray = foo; (the self. syntax calls a property, which in many cases will correctly retain the thing you've assigned). In an ARC project, they'll generally have the same behavior, and there's less room for error.
Personally, in my ARC projects, I do not use the self. syntax from within a class, since it's just extra typing for the same effect. This ties in nicely with the new usage of #property, where you're no longer required to write a #synthesize block, and Objective-C will automatically generate an ivar for you, with the name of your property prefixed by an underscore, i.e. _myPropertyName. That makes it very clear visually when you're accessing code from outside the class (crossing the encapsulation boundary), where things will look like foo.bar = baz; versus inside the class, where it's just _bar = baz;.
IMHO, clearly, a function call would incur an extra overhead.
you would have to allocate an object pointer (though minimal) over the stack (extra memory)
Have to pass it (extra processing)
Property is actually a small function call unless you have made customizations to the getter. I also assume that compiler may have its own optimizations put in place for such accessors so that you can access them with minimal overhead, though I do not have any source to cite this.