iOS >> How to Create a "Place Holder" Array for Objects that Were Not Yet Alloc/Init - ios5

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.

Related

UISearch bar in two NSMutables arrays

I see item UISearchBar search two arrays and very much items and not found solution, the problem its similar, have two NSMutablesArrays "subdetail" and "sublista" its show in Cell cell.textLabel and cell.detailTextLabel.
I try UISearchbar but i tray with NSPredicate and not run, try with NSRange and have more errors, i am desperate.PLEASE help me, any comments agree.
This its my code in Search:
- (void)filterContentForSearchText:(NSString*)searchText scope:(NSString*)scope
{
NSMutableDictionary *playas = [NSMutableDictionary dictionaryWithObjectsAndKeys:sublista, #"nombre", subdetail, #"localidad", nil];
[alldata addObject:playas];
for(NSDictionary *playas in alldata){
NSString *nombre = [playas objectForKey:#"nombre"];
NSRange nombreRange = [[nombre lowercaseString] rangeOfString:[searchText lowercaseString]];
if(nombreRange.location != NSNotFound)
[filteredList addObject:playas];
}
}
Add rest of code .m and .h
https://dl.dropboxusercontent.com/u/6217319/BuscarViewController.h
https://dl.dropboxusercontent.com/u/6217319/BuscarViewController.m
Thanks in advance.
BEST REGARDS
Your code has a lot of issues with it. I don't know which ones are actually breaking it, but any of these issues could be causing severe problems.
First, the code sample you provided doesn't provide declarations for a lot of hte objects you're referencing. No way this could possibly compile as given. If these are properties of the view controller instance, you need to use the accessor methods -- self.alldata or [self alldata], whichever you prefer.
Second, it looks like you're just adding to these properties. If you never reset their contents, every time this method is called, you're going to increase the size of your data set -- looking at your code, possibly recursively.
Third, you try to merge the two datasets together, and then try to search through only one of them. Either don't merge, or search through both seperately and then merge the results. As it is, what you're doing won't work.
Fourth, your table view should really only be displaying one type of data, so you shouldn't need to merge.
Edit:
Based on the code samples you've provided, your entire VC is going to need restructuring. Given how much of your code is written in what appears to be spanish, I'm doing a bit of guesswork at what you're actually doing.
First off, assuming you're using a modern version of xcode, get rid of the #synthesize in the .m file (it's no longer needed anymore). That will cause every single place you're using the actual ivar instead of a proper getter to turn into an error, so you can fix them quickly. iVars will by default use a prefixed underscore of their property name, so you can still access them if you have to -- but only by explicitly accessing the ivar instead of the property.
Second, you should restructure how you handle the data. I don't know where you get your data, but it looks like the various objects are fairly consistent. You should go ahead and either create a new class to hold all the data, or just put them all into a single dictionary. At that point, the 'alldata' property should, in fact, be an array of all valid data. What you should do is then have a filtered list of data (filteredData would be a good name), and you place whatever data matches the search criteria in there. Just remember to either reload the table or update it appropriately as items move into and out of the filtered list.

iPhone - Changing an array while it's enumerated

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.

Checking which game levels have been completed iPhone

I am writing this game with hundreds of levels, but in one of my menus I want to let the user 'quick select' any level by pressing the icon for it (like springboard, except instead of apps, ill have levels). But I also want a little tick to show up in the icon if the level has been completed.
What is the best way of checking which (of my 300+ levels) has been completed, in a totally different file?
NSUserDefaults seems a very clumsy way of doing this. I was thinking more like a loop? But I have no Idea how to do it.
Thanks for your help!
You can always store NSArray object in NSUserDefaults. It could be either boolean array indicating whether level completed or not, or just the list of completed levels.
Creating a separate file for it seems like too much hassle to me.
You can find the list of things you can store in NSUserDefaults in its documentation.
edit
Array of booleans could be created like this (since bool is a primitive type, we wrap it into NSNumber)
NSMutableArray *passedLevels = [NSMutableArray array];
[passedLevels addObject:[NSNumber numberWithBool:TRUE]];
if ([[passedLevels objectAtIndex:0] boolValue]) {
// level passed
}
You can find more methods to manipulate NSArray and NSMutableArray in their documentation.

Core Data - How to check if a managed object's properties have been deallocated?

I've created a program that uses core data and it works beautifully.
I've since attempted to move all my core data methods calls and fetch routines into a class that is self contained. My main program then instantiates that class and makes some basic method calls into that class, and the class then does all the core data stuff behind the scenes. What I'm running into, is that sometimes I'll find that when I grab a managed object from the context, I'll have a valid object, but its properties have been deallocated, and I'll cause a crash. I've played with the zombies and looked for memory leaks, and what I have gathered is it seems that the run loop is probably responsible for deallocating the memory, but I'm not sure.
Is there a way to determine if that memory has been deallocated and force the core data to get it back if I need to access it? My managedObjectContext never gets deallocated, and the fetchedResultsController never does, either.
I thought maybe I needed to use the [managedObjectContext refreshObject:mergeData:] method, or the [managedObjectContext setRetainsRegisteredObjects:] method. Although, I'm under the impression that last one may not be the best bet since it will be more memory intensive (from what I understand).
These errors only popped up when I moved the core data calls into another class file, and they are random when they show up.
Any insight would be appreciated.
-Ryan
Sounds to me like you are not retaining objects you want to keep hanging around. If you are doing something like this:
NSArray *array = [moc executeFetchRequest:request error:&error];
you do not own the returned array and it will most likely disappear when the current autorelease pool is drained. This will occur when the run loop finishes processing the current event.
All this is speculation. If you want a proper answer, you need to post your code.
It's hard to know what the problem is based on your description, but you might want to look at the Core Data memory management guide. You shouldn't have to worry about memory management for managed objects and their entities (they're fetched and faulted automatically). When you talk about "properties," do you mean custom properties backed by ivars? If so, these should be released in didTurnIntoFault and allocd as needed (probably in the accessor).
I was struggling with a similar issue. I'm using a managed object class and want to set its properties dependent on user input. But the sometimes the properties and sometimes the whole managed object were deallocated.
After reading the Apple documentation http://developer.apple.com/library/IOs/#documentation/Cocoa/Conceptual/CoreData/Articles/cdMemory.html the chapter "The Role of the Managed Object Context" I learned that managed objects are released each run loop completes.
And there is the golden advice to set
[myMangedObjectContext setRetainsRegisteredObjects:YES];
(I had to set it in the init method (initWithNibName for me) of my view controller.)
You should also regard to retain only the objects you need to as explained in the documentation. But read it yourself.
If I'm not right please correct me.
I also made a class that handles all my CoreData fetching and stuff. I ran into a couple of gotcha's, so here are some tips. (If I am making any memory management errors in these examples, please let me know.)
Two things:
1) Made a "fetchFiredObject" method in the CoreData handler class. So when I want to get a managedObject that has all its variables and is a "fully feathered bird" so to speak, instead of doing:
aManagedObject *myManagedObject = [myCoreDataHandler.managedObjectStorageArray objectAtIndex:1];
int x = myManagedObject.someVariable.intValue;
instead I do:
aManagedObject *myManagedObject = [myCoreDataHandler fetchFiredObjectAtIndex:1];
int x = myManagedObject.someVariable.intValue;
And in myCoreDataHandler's fetchFiredObjectAtIndex:i method, we're going into the array, finding the object key at index i, then doing a fetchRequest for that object key, and returning the freshly-fetched managedObject so that it won't have been faulted or deallocated, etc. :D
2) When I create a new child viewController, I populate its "myCoreDataHandler" value from the parent upon creation. However, this happens on a subsequent line of code after the line of code that creates the new viewController. Therefore, any code in the child's viewDidLoad that tries to use myCoreDataHandler's methods will return empty objects because viewDidLoad completes before the parent's next line of code where it sets the values of globals in the child object. So make sure you are not accessing your "Core Data handling object" from within viewDidLoad or anything local methods called by viewDidLoad! Instead call them from the parent after creating the new viewController.

Memory Management Basics - Objective C

I have a general question about objects, memory, and retaining.
I am not a complete newb (I have apps for sale on the iTunes Store) but something must have slipped past me. I work with the Google Docs API, and yesterday I was downloading a spreadsheet feed, and enumerating the results, namely, the Spreadsheet Record Feed.
After enumerating and adding objects to a dictionary, the dictionary got added to an array before the loop went to the next Record. So after 5 times through, the array had 5 objects, one dictionary per record, with values from each. Weirdly, at the end, the Array had 5 copies of the same information. Each time through the loop, the dictionary changed, like it was supposed to, but when I inserted it into the array, the other objects in the array changed to match.
I looked through some stuff on StackOverflow and found a suggestion to try this:
[array insertObject:[dictionary copy] atIndex:0];
That fixed it. Adding the copy method made everything work like normal.
I'm just wondering why.
Usually, when an object is put into an array, it's kept intact even if the original object is modified or destroyed.
You are mistaken. Arrays (and all other container classes in Cocoa) never work like that. They only store a reference to the objects they contain (and retain them) so any changes in the original objects will be reflected if you retrieve them from the array (because they are the same objects).
Sure, by calling copy you are creating a copy of the dictionary so now you are dealing with separate objects. At the same time, you are now leaking memory because you are responsible for releasing an object that is returned from copy.
Also, bear in mind that copy only makes a shallow copy, so the actual content of the copied dictionaries is not being copied. If you change the dictionaries' contents, these changes will be reflected in both dictionaries (the "original" one and the copied one you have added to the array).
When you insert an object (let's call it X) into an array, what actually gets placed into the array is a copy of the pointer to X, and not a copy of X itself. X is sent a retain message so that the array can hold on to it, but X is not sent a copy message. This means that changes to X later on will affect the object "stored" in the array.
WARNING: The suggested solution results in a substantial memory leak, since the copied data is never released. A better solution is to autorelease the copied array, so that it will be released when the array is released.
[array insertObject:[[dictionary copy] autorelease] atIndex:0];
Or, for iPhone code (in which autorelease can be bad, especially in loops):
NSDictionary * newDict = [dictionary copy];
[array insertObject:newDict atIndex:0];
[newDict release];
UPDATE: Be sure to read Ole Begemann's answer as well. He makes an excellent point about deep vs. shallow copies of the dictionary.