Inserting Objects into NSMutableArray - iphone

Currently, I have edited a delegate function that adds Exercise objects to an NSMutableArray. However, I would not like to add duplicate objects, instead, if the object is already in the array, i'd like to simply access that particular object.
Here is my code:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
NSString *str = cell.textLabel.text; // Retrieves the string of the selected cell.
Exercise *exerciseView = [[Exercise alloc] initWithExerciseName:str];
WorkoutManager *workoutManager = [WorkoutManager sharedInstance];
if (![[workoutManager exercises] containsObject:exerciseView]) {
[[workoutManager exercises] insertObject:exerciseView atIndex:0];
[self presentModalViewController:exerciseView animated:YES];
NSLog(#"%#", [workoutManager exercises]);
}
else {
[self presentModalViewController:exerciseView animated:YES];
NSLog(#"%#", [workoutManager exercises]);
}
}
I thought this would work, however, when I ran my code and NSLogged my array, it showed that when I clicked on the same cell, two seperate objects were created. Any help?

Each time you call
Exercise *exerciseView = [[Exercise alloc] initWithExerciseName:str];
it create a new (distinct) exerciseView object. So even though the exercise name may be the same as the name for an exercise object in your exercises list, it is a brand new object so when you call containsObject the result will always be false and your new object will be added to the array.
Perhaps you should store a list of the NSString exerciseName in your workout manager instead?

I would say this is your culprit:
Exercise *exerciseView = [[Exercise alloc] initWithExerciseName:str];
You're creating a new object each time so technically, it's not in the array. The containsObject method is just iterating through the array and calling isEqual on each object. I haven't tested this but theoretically, in your custom Exercise object, you could override the isEqual method to compare the exercise name properties and return true if they match. See, EVERYTHING has to match up when you are using containsObject so even if all the properties are the same, the objectid is not.
Easy fix without having to see your Exercise implementation:
Exercise *exerciseView = nil;
For(Exercise *exercise in [[WorkoutManager sharedInstance] exercises]){
if(exercise.exerciseName == str) {
exerciseView = exercise;
break;
}
}
if(exerciseView == nil) {
exerciseView = [[Exercise alloc] initWithExerciseName:str];
[[workoutManager exercises] insertObject:exerciseView atIndex:0];
}
[self presentModalViewController:exerciseView animated:YES];
Hope this helps explain WHY its happening. I didn't test this code since there are some missing pieces but you should get the idea. Have fun!

WorkoutManager *workoutManager = [WorkoutManager sharedInstance];
Exercise *temp = [[Exercise alloc] initWithExerciseName:str];
for(id temp1 in workoutManager)
{
if( [temp isKindOfClass:[Exercise class]])
{
NSLog(#"YES");
// You Can Access your same object here if array has already same object
}
}
[temp release];
[workoutManager release];
Hope, this will help you....

Related

Can't understand why my tableview with GCD is crashing

I've just finished re-writing this, and covered every conceivable angle I can think of. I don't know why this is crashing. Perhaps somebody could help me figure it out.
This is the cellForRowAtIndexPath code:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
JHomeViewCell *cell = (JHomeViewCell *)[tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[JHomeViewCell alloc] initWithStyle:UITableViewCellStyleDefault
reuseIdentifier:CellIdentifier];
cell.delegate = self;
}
cell.cellContent.cellInfo = [self cellInfoForCellAtIndexPath:indexPath];
if (cell.cellContent.cellInfo.thumbnailsComplete == YES || cell.cellContent.cellInfo.thumbnailsBeingCreated == YES) {
[cell.cellContent setNeedsDisplay];
}
else {
[cell.cellContent setup];
}
return cell;
}
And in cellContent, there's this setup method:
-(void)setup {
[self setNeedsDisplay];
self.cellInfo.thumbnailsBeingCreated = YES;
NSManagedObjectID *entryID = self.cellInfo.objectID;
dispatch_queue_t cellSetupQueue = dispatch_queue_create("com.Journalized.SetupCell", NULL);
dispatch_async(cellSetupQueue, ^{
NSManagedObjectContext *newMoc = [[NSManagedObjectContext alloc] init];
NSPersistentStoreCoordinator *coordinator = [[CoreDataStore mainStore] context].persistentStoreCoordinator;
[newMoc setPersistentStoreCoordinator:coordinator];
NSNotificationCenter *notify = [NSNotificationCenter defaultCenter];
[notify addObserver:self
selector:#selector(mergeChanges:)
name:NSManagedObjectContextDidSaveNotification
object:newMoc];
Entry *entry = (Entry *)[newMoc objectWithID:entryID];
[newMoc save:nil];
int i = 0;
while (i < self.cellInfo.numberOfThumbnailsToDraw) {
NSLog(#"number of thumbnails: %i %i %i", self.cellInfo.numberOfThumbnailsToDraw, entry.media.count, i);
Media *media = [entry.media objectAtIndex:i];
UIImage *image = [media getThumbnail];
BOOL success = [newMoc save:nil];
//NSLog(#"time: %# success: %i", entry.entryTableInfo.creationTimeString, success);
[self.cellInfo.thumbnails setObject:image forKey:[NSNumber numberWithInt:i]];
i++;
}
[[NSNotificationCenter defaultCenter] removeObserver:self];
dispatch_async(dispatch_get_main_queue(), ^{
self.cellInfo.thumbnailsComplete = YES;
[self setNeedsDisplay];
});
});
dispatch_release(cellSetupQueue);
It crashes on the line:
Media *media = [entry.media objectAtIndex:i];
With the error:
index 1 beyond bounds [0 .. 0]
The NSLog above that...
NSLog(#"number of thumbnails: %i %i %i", self.cellInfo.numberOfThumbnailsToDraw, entry.media.count, i);
Gives the result:
number of thumbnails: 2 1 1
Which sort of explains the crash, except that value is set in the [cellInfoForCellAtIndexPath:]; method, like so:
cellInfo.numberOfMediaItems = entry.media.count;
cellInfo.numberOfThumbnailsToDraw = MIN(cellInfo.numberOfMediaItems, 3);
I really don't know where the problem is occurring, or why it's occurring, but I can't move on with my app until this part is fixed.
Well numberOfThumbnailsToDraw is 2 meaning the while loop will do 0, 1, but the count of your entry.media is only 1 so it only has a 0 index so of course it'll crash.
[managedObjectContext obtainPermanentIDsForObjects:self.cellInfo error:nil];
[managedObjectContext save:...];
NSManagedObjectID *entryID = self.cellInfo.objectID;
You need to make sure that
1. You have a permanent object ID; not a temporary one
2. The object is persisted so that it appears on the new MOC.
It looks like you are querying entry.media.count where entry is a pointer into one MOC, and then you are querying it from another. You are asking using the objectID, which is reasonable.
However, when the new MOC gets the object, it does not see the same values as you saw in the other MOC. Most likely, this means that you have not properly saved the other MOC.
What happens if you execute a fetch for the object on the new MOC?
Also, I would enable core data debugging (-com.apple.CoreData.SQLDebug 1) in command line options. This will log to the console what's going on underneath. You should see the SQL statements for the underlying database logged to the console.
Also, you are saving your MOC without ever making any changes to it, which leads me to believe you are a bit confused on how your many MOCs are working together.

NSMutable Array: Getting "out of scope" Status After Mutable Copying

I have a SOAP service and I generated classes and functions on SudzC.com.
So I'm using the soap functions they generated, it returns an NSMutableArray with objects that are inherited by my custom class(which is generated by them, too).
So far everything's good. My values are getting into the array and I could see any property of any object with one condition: Only inside of the function that's handling the service.
Just to make it clear, here is the code:
- (void)viewDidLoad
{
SDZGeneratedWebService* service = [SDZGeneratedWebService service];
service.logging = YES;
[service callMyData:self action:#selector(callMyDataHandler:) dataId: 1];
[super viewDidLoad];
}
- (void) callMyDataHandler: (id) value {
// Handle errors
if([value isKindOfClass:[NSError class]]) {
NSLog(#"%#", value);
return;
}
// Handle faults
if([value isKindOfClass:[SoapFault class]]) {
NSLog(#"%#", value);
return;
}
// Do something with the NSMutableArray* result
NSMutableArray *result = (NSMutableArray *)value;
MyCustomClass *myObject = [result objectAtIndex:0];
NSLog(#"%#", myObject.myProperty); //Works Great
}
Like I said, so far everything's perfect. But I need to use the data outside of this function.
So in my .h file, I created an array like NSMutableArray *myDataArray;
When I intend to copy the result array to myDataArray, it copies the objects(I can see that the myDataArray.count value is equal to result array's) but all the objects are "out of scope". So I cannot use them.
I also tried to copy all objects by indexes in a for loop, nope, the objects are getting their values, but when I "addObject" to myDataArray, same, out of scope.
What is wrong here? Can't I generate an array of a custom class this way?
Edit: The code I'm generating myDataArray:
myDataArray = [[NSMutableArray alloc] init];
[myDataArray removeAllObjects];
for (int i=0; i<((NSMutableArray *)result).count; i++) {
MyCustomClass *myObject = [result objectAtIndex:i];
[myDataArray addObject:myObject];
[myObject release];
}
[self.tableView reloadData];
} //(End of callMyDataHandler function)
I before tried this way, too:
[myDataArray removeAllObjects];
duyurular = [result mutableCopy];
} //(End of callMyDataHandler function)
You can copy objects from one array to another using this method:
NSArray *source;
NSArray *dst = [[NSArray alloc] initWithArray:source];
In your code you should remove line: [myObject release]; and I would better call [((NSMutableArray *)result) count] rather then using dot notation.

how pass array value on other class for display data in iphone

Hi friends thank for helping to me
I have doubt when i pass one array value for display on other controller class in tableView so I get nil value on that controller how to take array value on that class of other controller for display purpose
my lstAirports is a array which created on Airport.h and my Airport.h is simple class is not delegate the code of this class:
- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
loginStatus = [[NSString alloc] initWithBytes: [webData mutableBytes] length:[webData length] encoding:NSUTF8StringEncoding];
[connection release];
NSString *regexString = #"Stations\\[""(.*)""\\] = new Station\\((.*)new Array\\((.*)\\)\\);";
matchArray = [loginStatus arrayOfCaptureComponentsMatchedByRegex:regexString];
//NSLog(#"matchArray: %#", matchArray);
lstAirports = [[NSMutableArray alloc] initWithCapacity:[matchArray count]];
for (int i = 0; i < [matchArray count]; i++) {
airport *air=[[airport alloc]init];
//code
NSString *temp=[[matchArray objectAtIndex: i] objectAtIndex: 1];
NSString *newString=[temp stringByReplacingOccurrencesOfString:#"\"" withString:#""];
arrParts=[newString componentsSeparatedByString:#","];
air.Code =[arrParts objectAtIndex:0];
//air.Code = [[matchArray objectAtIndex: i] objectAtIndex: 1];
NSLog(#"air.Code: %#\n",air.Code);
//name
temp=[[matchArray objectAtIndex: i] objectAtIndex: 2];
newString=[temp stringByReplacingOccurrencesOfString:#"\"" withString:#""];
arrParts=[newString componentsSeparatedByString:#","];
air.Name=[arrParts objectAtIndex:2];
NSLog(#"air.Name: %#\n",air.Name);
//destination airports
temp=[[matchArray objectAtIndex: i] objectAtIndex: 3];
newString=[temp stringByReplacingOccurrencesOfString:#"\"" withString:#""];
arrParts=[newString componentsSeparatedByString:#","];
air.DestinationAirports =arrParts;
NSLog(#"air.DestinationAirports: %#\n",air.DestinationAirports);
[lstAirports addObject: air];
NSLog(#"lstAirports: %#\n",lstAirports);
//NSString *str=
//[air release];
}
}
- (void)dealloc {
[super dealloc];
[loginStatus release];
//[lstAirports release];
[webData release];
// [window release];
}
When I pass this array on my `Odselectioncontroller.m` then I get nil value of array where I am wrong friends please help me out this is my controller class code
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
// Return the number of rows in the section.
return obj.lstAirports.count;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
}
airport *a=(airport*)[obj.lstAirports objectAtIndex:indexPath.row];
NSLog(#"str:%#",a);
cell.textLabel.text =a.Name;
and `Airport` is other class where i am create name property for fetch value name from array in yhis class
You are always creating new instance of your Airports class obj which will return you nil value always.
If you want to pass a array from one to other then you can do it by two ways-
make your array global by using extern keyword.
you can define a array in second class as a property and then can set it.
for more you can refer this -
Passing data between classes using Objective-C
DO one thing declare the NSMutable Array in AppDelegate and synthesize the array and using this array to store objects in any class and use this array to display in any class directly by using appDelegate.ArrayName Hope it helps You :)
Here you can do like,
Airport.h class as Sigleton and use .
Otherwise
Declare a Array in APPDelegate and access it in you needed class by sharedObject mechanism
Either you can pass the array using an array object which is synthesized in the class. Another option is to have a method(which takes a NSArray object as parameter) in the class you want to populate and call the method on your first class passing the array as parameter.
Your code also requires a slight change in the dealloc method. Its advised not to call [super dealloc]; before releasing the objects of the class. Always call [super dealloc]; at the end after releasing all objects.

Get all object properties from delegate array

I am successfully retrieving an array from my delegate, however I am struggling to get all of the objects properties, so in my AppDelegate:
arrayOne = [[NSMutableArray alloc] init];
NSMutableArray *tempArray1 = [self myArray];
// Add names to arrayOne
for (MyInfo *info in tempArray1) {
[arrayOne addObject:info.name];
}
I then retrieve this in my MainView:
cell.textLabel.text = [delegate.currentlyUsedArray objectAtIndex:row];
This works fine, but myArray contains other properties such as: info.age and info.height — how do I get these to another textLabel? Do I have to do the same approach as above or is there a more efficeint way?
Why can't you just add info to the array.
for (MyInfo *info in tempArray1) {
[arrayOne addObject:info];
}
and later where you are setting it.
MyInfo *info = (MyInfo*)[delegate.currentlyUsedArray objectAtIndex:row];
cell.textLabel.text = info.name;
// Other fields should also accessible directly such as info.age and info.height.
medley,
You can make method of appDelegate myArray public and get your info values right from where you need it, in this case in cellForRowAtIndexPath: method.
Following Zapko's answer, your code in MainView would look like this to access the various properties of a MyInfo object in the myArray property of your delegate object:
cell.textLabel.text = [(MyInfo *)[delegate.myArray objectAtIndex:row] name];
cell.ageLabel.text = [(MyInfo *)[delegate.myArray objectAtIndex:row] age];
cell.heigtLabel.text = [(MyInfo *)[delegate.myArray objectAtIndex:row] height];

Strange behaviour when setting property in iPhone app

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
PushOnStackViewController *vc = [[PushOnStackViewController alloc] init];
vc.key = [self.keys objectAtIndex:[indexPath row]];
[self.navigationController pushViewController:vc animated:YES];
}
and
in the init method of the PushOnStackViewController class I have
- (id)init {
self.navigationItem.title = key;
NSDictionary *dict = [[NSDictionary alloc] initWithContentsOfFile:[[NSBundle mainBundle] pathForResource:#"texts" ofType:#"plist"]];
self.keys = [dict objectForKey:key];
[dict release];
NSLog(#"%#", self.key);
NSLog(#"%i", [self.keys count]);
return self;
}
But why can't I access the self.key? It returns null, even though it has been set(it is a string).
When I access it in viewDidLoad it returns the correct value...anything I haven't read, or am I doing anything wrong?
Thanks in advance.
You can't access self.key inside the -init function because at that point it hasn't been set yet. you are setting it afterwards:
PushOnStackViewController *vc = [[PushOnStackViewController alloc] init]; // init runs here.
vc.key = [self.keys objectAtIndex:[indexPath row]]; // but you don't set the key property until here.
You might try adding a "key" parameter to the init function, like so:
-(id)initWithKey:(NSString*)key {
self = [super init];
if (self) {
self.key = key;
...etc...
}
return self;
}
Your init method is called before you set the property. Get rid of that init method and move your code into viewDidLoad to ensure that it's called after you've done all the property setup.
Don't create new init method for a UIViewController unless you know what you're doing. It's much easier to create a property (like you've done) and access that property inside the viewDidLoad method.