NSMutableArray addOject rewrites data - iphone

I know there are a lot of questions based on the same topic. But none seem to be solving my problem.
I have a NSMutableArray _buttonArray and a NSMutableDictionary _singleBtn.
When I press a button, I add the dictionary to the array. But the array is getting overwritten.
[_singleBtn setObject:scanBarCodeButton.titleLabel.text forKey:#"text"];
[_singleBtn setObject:NSStringFromCGRect(scanBarCodeButton.frame) forKey:#"frame"];
[_buttonArray addObject:_singleBtn];
In the first iteration, I get the following:
{
frame = "{{20, 40}, {50, 40}}";
text = abc;
}
Now if I add the text "xyz", it gives me:
{
frame = "{{20, 90}, {80, 40}}";
text = xyz;
},
{
frame = "{{20, 90}, {80, 40}}";
text = xyz;
}
I've done the allocation of both the array and the dictionary in my viewDidLoad

This is not an overwrite of a previously added object - the reason you see this is that you have added a reference to the same object two times. Your NSMutableArray looks like this:
[_singleBtn, _singleBtn]
NSMutableArray does not make copies of objects that you insert, so you need to take care of making new objects before inserting them.
One way of making a copy is passing _singleBtn to a method that copies it into a new dictionary, like this:
[_buttonArray addObject:[NSMutableDictionary dictionaryWithDictionary:_singleBtn]];

Related

combine UITextFields input into one UITtextField

Im new to xcode and objective c. I have asked this question three times and still can't find a good method or answer. I have several uitextfields that accept user input and adds it to the combinedtextField in order of IBAction used.ie user inputs big in one field,bad in the next one and boy in the third and the result is big bad boy in the combinedtextField.
-(IBAction)addtextField1: (id)sender
{
combinedtextField.text = [NSMutableString stringWithFormat:#"%# %#",
combinedtextField.text,textField1.text];
}
-(IBAction)addtextField2: (id)sender
{
combinedtextField.text = [NSMutableString stringWithFormat:#"%# %#",
combinedtextField.text, textField2.text];
}
-(IBAction)addtextField3:(id)sender
{
combinedtextField.text = [NSMutableString stringWithFormat:#"%# %#",
combinedtextField.text,textField3.text];
}
Now this is where it gets interesting.I need to be able to remove the selected text from the combinedtextField.
-(IBAction)removetextField1:(id)sender
{
//////////????????????////////////////
}
-(IBAction)removetextField2: (id)sender
{
//////////????????????////////////////
}
-(IBAction)removetextField3: (id)sender
{
//////////????????????////////////////
}
If I tap the removetextField2 button it would remove the corresponding text(bad) from the combinedtextField and then it would read (big boy)
Ive looked into nsarrays,nsdictionarys and other methods and have got no where.
Need some way of possibly tagging the input and removing it that way. Example code would be great and very much appreciated.
You've left out some important details about your app, so I'm making some guesses about how it should work.
Perhaps what you should do is keep a mutable array of all of the fragments that have been added to the combined string:
#implementation MyViewController {
    NSMutableArray *fragments_;
}
- (void)viewDidLoad {
[super viewDidLoad];
fragments_ = [[NSMutableArray alloc] init];
}
When one of the add buttons is tapped, you append the corresponding field's text to the array and recompute the combined string:
- (IBAction)addTextField1:(id)sender {
[fragments_ addObject:textField1.text];
[self updateCombinedTextField];
}
- (void)updateCombinedTextField {
combinedTextField.text = [fragments componentsJoinedByString:#" "];
}
When one of the remove buttons is tapped, you try to remove the corresponding field's text from the fragments array and recompute the combined string:
- (IBAction)removeTextField1:(id)sender {
[fragments_ removeObject:textField1.text];
[self updateCombinedTextField];
}
That will remove all occurrences of field 1's text from the fragments array. If you just want to remove one instance, you will need to use indexOfObject: (or one of its variants) followed by removeObjectAtIndex:.
You can't do it in a very trivial way (without anything to add, just 1stroke magic function). But, there's the easy way, which i'd possible gone for.
If you don't need to do it a lot of times, and / or the text is quite small (not like a 500 pages book), then:
Create a boolean array named mark, and mark[i] should mark the i'th text field as 'added'. Then, create a function named reloadCombinedTextField, which creates it again, depended of the mark array. (if mark[i] == true, then we add a textfield's text, otherwise not)
Then, just mark or unmark the needed text fields in every function and call the reload function in the end of every call.
Altho, there is another way, but it can be wrong in situations where your text fields have the same text. The thing is, you just search in your combined text field the text from selected text field (for example, with [NSString rangeOfString] method) and remove it.
If you are going to do it often and the text is really big, then it goes much more complicated. But i'm quite sure, that you won't do this on iOS.

xcode iPhone array and dictionary [noob]

I'm sorry for this (probably very) noob question, but i've been asked about this and can't see what's wrong (i'm java tought..)
This is what I have, data is loaded via JSON:
NSDictionary *myvalues = [myres objectForKey:#"0"];
this is the content if I output via NSLog:
({id = "1a";myval = 5;},
{id = "2b";myval="24.6";})
how do I iterate through myvalues and how do I get the values id and myval? Something like this i'm getting stuck:
for (NSArray* myvals_array in myvalues)
First it looks like the returned value is an Array, the content inside of the parentheses() denotes this. So I would try and set it as such instead of a Dictionary. Then you can enumerate through the array of dictionary's and get each dictionary inside:
for (id object in myvalues) {
NSDictionary *currentObject = (NSDictionary*)object;
NSString *myID = [currentObject valueForKey:#"id"];
NSString *myValue = [currentObject valueForKey:#"myval"];
NSLog(#"ID:%# VALUE:%#",myID,myValue);
}
This will enumerate through the array and create a dictionary for each entry, then get the values for each of the two elements inside. I just NSLog() them here but you can do whatever you want with the values.

How to refer to an object in a NSDictionary that is in a NSArray

When I NSLog the array I get this:
(
{
content = "content a";
id = 452069;
timestamp = 1313341470;
},
{
content = "content b";
id = 451498;
timestamp = 1313261505;
},
etc...
)
How do you refer to specific index's? For example how would you get the content for the second index.
I've tried [[myArray objectAtIndex:1]objectForKey:#"content"] but that crashes the program.
Also doing [myArray objectAtIndex:1] crashes the program as well.
According to your edit your array is likely over released. Make sure your array is properly retained, if it uses a property make sure the property is set to copy or retain and if you set it internally be sure to use self.myArray = ...; and not myArray = ...'.
Have you tried -valueForKey:? The item at that index is not an object but a value.

Core data only storing last object of JSON feed

I´m using Core Data as local storage in my app. I´ve set it up properly and made subclasses of NSManagedObject for each entity. However, when I´m trying to insert values into my store, it only inserts the last object from my JSON feed.
res = [JSONHandler requestJSONResponse:jsonString];
shows = [res valueForKeyPath:#"Show.Name"];
NSUInteger showIndex = 0;
for(NSString *showName in shows){
showObject = [NSEntityDescription insertNewObjectForEntityForName:#"Show" inManagedObjectContext:managedObjectContext_];
showObject.name = showName;
showObject.iD = [[res valueForKeyPath:#"Show.Id"]objectAtIndex:showIndex];
showObject.desc = [[res valueForKeyPath:#"Show.Description"]objectAtIndex:showIndex];
showObject.activityType = [[res valueForKeyPath:#"Show.ActivityType"]objectAtIndex:showIndex];
showIndex++;
}
This only stores the last object from my JSON feed. Any idea why?
EDIT: It works fine when I do this:
res = [JSONHandler requestJSONResponse:jsonString];
shows = [res valueForKeyPath:#"Show.Name"];
NSUInteger index = 0;
for(NSString *showName in shows){
show = [NSEntityDescription insertNewObjectForEntityForName:#"Show" inManagedObjectContext:managedObjectContext_];
[show setValue:showName forKey:#"name"];
[show setValue:[[res valueForKeyPath:#"Show.Id"]objectAtIndex:index] forKey:#"iD"];
[show setValue:[[res valueForKeyPath:#"Show.Description"]objectAtIndex:index] forKey:#"desc"];
[show setValue:[[res valueForKeyPath:#"Show.ActivityType"]objectAtIndex:index] forKey:#"activityType"];
index++;
}
It´s basically the same thing, isn´t it? But I want to use subclasses of NSManagedObject instead of doing like I did above. Because in the snippet above show is NSManagedObject *show instead of what it should be: Show *show.
How many shows are there? You can find this by doing: NSLog(#"Number of shows: %d.", shows.count);, assuming that shows is an NSArray. It could be that your Core Data code is fine and the JSON parsing itself is at fault.
EDIT: Also, are you correctly saving the changes to the persistent store?
Usually when you see just one of several objects being saved like this, the problem is that a relationship that should be to-many is improperly set as to-one. No matter how many objects you try to add to the relationship, only the last one is set because the relationship can hold only one value.
I think in this circumstance the problem is most likely in the code of the custom subclass instead of the data model itself given that the data model works with generic NSManagedObjects.

How to sync a section in a MutableArray with UITextView

I have one MutableArray (NSMutableArray *NoteBook;) in which I would like to store Notepages (I set up an object called NotePage.m which simply contains one NSString *noteText and a method to setNoteText). I also have an integer to keep track of my pages (NSUInteger currentPageCounter;).
I start my little program by setting up a new instance of NotePage:
NotePage *newPage = [[NotePage alloc] init];
[newPage setNoteText:#"Sample Text for a certain page..."];
I then copy this *newPage 3 times into my NoteBook Mutable Array:
[self.NoteBook insertObject:newPage atIndex:(self.currentPageCounter)];
This will give me 3 pages, at the indices 0,1,2. So far so good. Everything works splendid. But now comes the enemy, UITextView. First of all, I would like to display the contents of a page within my NoteBook in an UITextView. So I did this to sync one section in the MutableArray (e.g. page at index 0) with the UITextView which works fine:
NotePage *thisPage = [self.NoteBook objectAtIndex:self.currentPageCounter];
TextViewNote.text = thisPage.noteText;
The problem is, however, if I want to edit my UITextView and sync the updated text with the MutableArray. This is where the crashing happens... I have coded this in a separate method which can be clicked once the user is done editing the UITextView:
-(IBAction) savePage
{
NSString *tempString;
tempString = [NSString stringWithFormat:#"%#",TextViewNote.text];
NotePage *newPage = [[NotePage alloc] init];
[newPage setNoteText:tempString];
[self.NoteBook insertObject:newPage atIndex:(self.currentPageCounter)]; // e.g. at index 0 for page 1
[self.NoteBook removeObjectAtIndex:(currentPageCounter+1)]; // i.e. this is to remove the old page 1 which used to be at index 0 but now is at index 1
[self syncTextView];
[self syncCounter];
}
I guess there is a less cumbersome way (I'm still a beginner...) to simply replace an object at a certain index at a Mutable Array. As it stands now, it will simply crash once I try to move onwards to the next index position which is apparently not found anymore.
Thanks for any ideas!
I guess there is a less cumbersome way
(I'm still a beginner...) to simply
replace an object at a certain index
at a Mutable Array.
Indeed. Look at -[NSMutableArray replaceObjectAtIndex:withObject:].
Considering the error you posted, it sounds like you've got a bad pointer somewhere. The error is complaining that somewhere, a -[UITouchData length] message is being sent to an instance of NotePage. Turn on the 'Stop on Objective-C Exceptions' option in the debugger (under the Run menu). That should help you see where the problem is occurring.
NSMutableArray has a method replaceObjectAtIndex:withObject: that should do what you are trying to do.
You've got a memory management issue, however, unless you are calling release on the newPage after you add it to the array. Unless you are planning on making the NotePage class more complex, it might make sense simply to change the item's text rather than substituting a new object:
[[self.noteBook objectAtIndex:currentPageCounter] setNoteText:tempString];
(Also, be aware that inserting the newPage object into the array four times does not copy the object; it simply inserts the same reference four times. If you want four distinct objects, you will need to allocate four objects in a loop:
for(i = 0; i < 4; i++){
NotePage *newPage = [[NotePage alloc] init];
[newPage setNoteText:#"Dummy text"];
[self.notebook addObject:newPage];
[newPage release];
}