I have a mutable array that contains the sounds that are being played.
I have a continous process that parse that array to adjust volumes and some other things.
Sometimes, a new sound is played and must be added to that array just before it's play starts.
And sometimes, I have a crash because my array "was mutated while being enumerated".
How may I solve that ?
You can't easily change an array while it's enumerating.
Enumerate through the array and note the new sound to be added (using a variable, or a separate array if you need to note more than one). When the enumeration is finished, add the sound to the array.
Alternatively, make a copy of the array, enumerate the copy and add the sound to the original one when you need to.
It would be nice to see any code here. But according what you are saying, i think the problem lies in the way that you use to iterate through the array. I guess it looks like this:
for ( type *object in myArray) {
...
}
Now, as you exception tells you, you can't modify the array while doing this. If you, on the other hand, access the array's values via the indexes, it should work:
for (int i = 0; i < myArray.count; i++) {
[myArray objectAtIndex:i]...
}
Keep in mind however, that the indexes aren't 'stable' that way, especially if you remove objects.
Related
In my application, I create many instances of NSColorwell, and as I create each new instance, I assign it to an array of NSColorwells. By assigning the instances to an array, I maintain a reference to each of them so that I am able to manipulate the position and color of the NSColorwells. So far, so good. But when I no longer need the NSColorwells, I cannot delete them. What I really want to do is free up the memory that they have been using. I tried the removeAll() method for the array, but that merely cleared the array. No real surprise.
Is there a way to reclaim the memory?
I used removeFromSuperview(), which appears to free up the memory.
while (index < CW.count) {
CW[index].removeFromSuperview()
index += 1
}
CW.removeAll()
In a certain view I have a bunch of AVAudioPlayer properties, each one is supposed to be played upon a certain user action. While the selected AVAudioPlayer is played, if another AVAudioPlayer was played - it should stop.
To manage that, I've created an Array that holds all the AVAudioPlayer properties and upon user selection, before playing the selected AVAudioPlayer, I wish to go over all the AVAudioPlayers and stop them.
The problem is that the reasonable place to create the Array is at the beginning (let's say, in ViewDidLoad) and at this point none of the AVAudioPlayer properties went through alloc+init - so if I look at the Array in the debugger it shows as empty (number of objects = 0). Currently, I do the alloc+init action only when the user is actually selecting a certain AVAudioPlayer.
I can do alloc+init for all the AVAudioPlayers at the beginning as well, but that will take resources that are not necessarily required.
Is there a way to create this Array without taking the required resources? i.e. create the array with "empty" objects and later have them be allocated and initiated?
I have a similar situation. What I've been doing is:
NSArray *myArray = [NSArray arrayWithObjects:#"",#"",#"",#""];
in viewDidLoad (if my array is going to have 4 objects). Then as I have the information available, I do:
[myArray replaceObjectAtIndex:myLocationToAddValue withObject:myObject];
I got the idea for this looking at some code in a very old project written in a completely different language by someone else from my company. It seems to be working for what I need, and it does have the added benefit that I can loop through my array and check
if ([[myArray objectAtIndex:i] length] == 0)
to see where I have items already. I should note that the objects I'm adding are going to all be NSStrings - if this loops through and finds an object has been put into the array that isn't a string (or, more generally, doesn't have a "length" method), I'm guessing some nasty stuff would happen, but I haven't checked for that yet.
I'm certain there must be a much better solution, but I'll put it out there since there haven't been any answers to this yet. I figure a sloppy answer that seems to be working is better than no answer.
I have an 3 NSMutableArray objects that contain CMTime objects. How can I iterate through all three of them in an efficient manner and find out if there are duplicate values in all three? For example, I'm iterating through one of time and reading the value and storing it in x. Now, I want to see if x occurs (at any position) within the other two arrays. I tried looking for a contains method, but couldn't find one. I did come across filterUsingPredicate, but I'm not sure if this is the best way of doing it nor how to actually use predicates.
I tried looking for a contains method, but couldn't find one.
Use indexOfObject:
like this:
if ([array indexOfObject:object] != NSNotFound) {
// object found
}
else {
// object not found
}
You can use ([yourArray indexOfObject:x] != NSNotFound) in place of your missing contains method. However, if you're doing this quickly, often, or with a lot of elements, you should consider using NSMutableOrderedSet, which is ordered like NSMutableArray, but offers a quick and efficient contains method, as well as allowing quick operations like union and intersection, which might allow you to redesign your algorithm to iterate through your elements much less.
I want to add items to mutable array from a dictionary. Problem is I want to check existing array items before adding new item. If same item is already there in the array, I want to replace it. else add the new item.
How could I do it?
You could perhaps use an NSMutableSet rather than an NSMutableArray. The addObject method on NSMutableSet will only "add a given object to the set, if it is not already a member."
If you'd like to check membership before adding to the set anyway, you can check the result of:
[mySet containsObject:myObjectFromDictionary]
...which returns a simple BOOL value indicating whether the set already contains an object whose isEqual method returns true when your object is passed to it.
(For a little extra functionality, NSCountedSet will keep track of the number of objects added to the "set" for which isEqual: returns true)
You could compare the result of : [yourArray indexOfObject:yourObject]; against NSNotFound to know if the object is in the array.
It will give you the index of the object to replace, or if it is equal to NSNotFound, you will add it.
Objects equality is tested with isEqual: method.
NSArray class reference.
On the face of it, both Vincent's and Rich's answers are correct.
However, there is a conceptual issue in the original question that hasn't been addressed.
Namely, that "membership in an array" via indexOfObject: (or containsObject: in a set) is ultimately done by comparing the two objects using isEqual:.
If isEqual: returns YES, then the two objects better had damned well be functionally identical in your code or else you have other, significantly more serious, problems in your design and implementation.
Thus, the real question should be "How do I detect if an object is already in an array and not add it?" and Rich's and Vincent's answer are both still correct.
I.e. you should only need to check for presence and, if present, take no action.
(Note that there are esoteric situations where replacement is actually warranted, but they are both truly esoteric and not generally used within the context of a mutable collection)
I am using a search bar in my app and display some results below from an ext API.
The contents first get stored in an array "xyz" and each time the user types in the search bar, I removeAllObjects and reload the table.
The results are correct if the user types slow i.e. [xyz removeAllObjects] works fine...However if the user types very fast, [xyz removeAllObjects] does not seem to have any effect and duplicate items get appended to the array..
I am not sure how to fix this. Please help me. Thank you.
removeAllObjects is an entirely serial operation; that method doesn't return until the array is empty.
Therefore, there must be a thread in play and you are quite likely accessing a mutable array from multiple threads. Mutable arrays aren't thread safe. Fix the exclusivity and you'll fix your problem.
The easiest way is to separate the array being displayed from the array being computed. As soon as the computation is done, move the computed array to the display array and never mutate it again.
Why not create a new NSArray, point the results at that, and then release the old array. That way having duplicates will be impossible. Something like:
NSArray *newArray = [someObject newSearchResults];
NSArray *oldArray = xyz;
xyz = [newArray retain];
[oldArray release];