Edited UITableViewCell is being stored as a new cell - ios

I have a table view that has a data source in sync with Core Data. However, I'm having a problem. Whenever I edit or delete a tableview cell, and I reload the view, I see a copy of the tableview cell that was there before it was edited. Here's some code to make it clearer.
When the view first loads, it tries to get all the "SOCommands" from "SOModule" which has a one-to-many relationship. Then, it converts it into "SOCommandTemp", so that I can work with them without altering the database.
_serverModuleCommands = [[NSMutableArray alloc]initWithArray:[self.serverModule.socommand allObjects]];
for(int i=0;i<[_serverModuleCommands count];i++)
{
SOCommandTemp* newTemp = [[SOCommandTemp alloc]init];
newTemp.commandName = ((SOCommand*)[_serverModuleCommands objectAtIndex:i]).commandName;
newTemp.sshCommand = ((SOCommand*)[_serverModuleCommands objectAtIndex:i]).sshCommand;
[_serverModuleCommands replaceObjectAtIndex:i withObject:newTemp];
}
Then, when I'm editing cells, I call methods such as these:
[_serverModuleCommands addObject:commandValues]; //commandValues is in the form of SOCommandTemp
[_serverModuleCommands replaceObjectAtIndex:_selectedCommandCell.row withObject:commandValues]; //_selectedCommandCell is an ivar that is cleared immediately after use
Then, when saving, I convert the array into SOCommand by doing this:
for(int j=0; j<[_serverModuleCommands count]; j++){
SOCommand* newCommand = [NSEntityDescription insertNewObjectForEntityForName:#"SOCommand" inManagedObjectContext:self.managedObjectContext];
newCommand.commandName = ((SOCommandTemp*)[_serverModuleCommands objectAtIndex:j]).commandName;
newCommand.sshCommand = ((SOCommandTemp*)[_serverModuleCommands objectAtIndex:j]).sshCommand;
newCommand.somodule = newModule;
}
However, before this is called, I want to make sure that I'm saving only one array item, since I added and editing one cell, so I do this:
NSLog(#"Going to Save: %#",[_serverModuleCommands description]);
And sure enough, I get only 1 array item. Then, I do save it, and exit the view controller. But when the first line:
_serverModuleCommands = [[NSMutableArray alloc]initWithArray:[self.serverModule.socommand allObjects]];
is called again, I'm getting two values in its description, one for the original and one for the edited.
Any help would be great!
~Carpetfizz

In your saving segment, you create a new SOCommand object no matter if it already exist.
Why not just use the actual objects (SOCommand) and edit them, this will not alter your DB information until you save the context.
It will save you some grieve swapping back and forth between your objects.
If you cannot edit in context, you should pass the existing item objectID to your "temp" objects and if it exist, fetch this object from DB and make the update to the existing item:
NSManagedObjectID* oID = ((SOCommandTemp*)[_serverModuleCommands objectAtIndex:j]).objectID;
if(oID) {
SOCommand* cmd = (SOCommand*)[context existingObjectWithID:oID error:nil];
if (cmd) { //no error fetching the object
//update `cmd` with your new values
}
}

Related

Properties in my model are being duplicated for each item after adding to an array

I am creating a model and then adding that model to an array. However, once I add more than one item, some of the properties in my model ended up being duplicated.I have the following properties of type DrawnLayerModel:
model.overlay
model.fillcolor
model.linecolor
model.overlayString
OverlayString is the property that I'm most concerned with at the moment. Here is where I create the model object and add it to my array:
-(void)saveOverlay {
DrawnLayerModel *model = [self.drawnLayerModel initWithOverlay:self.mapView.overlays.lastObject fillColor:self.customFillColor lineColor:self.customLineColor overlayTitle:self.layerName];
[self.overlaysArray addObject:model];
for (DrawnLayerModel *model in self.overlaysArray) {
NSLog(#"Model ====> %#.", model);
NSLog(#"Title ====> %#.", model.overlayTitle);
}
}
Every time this button is pushed it adds a new model object:
- (IBAction)saveButtonPressed:(id)sender {
UITextField *textfield = alertController.textFields.firstObject;
self.layerName = textfield.text;
[self.helpers createSuccessAlertContoller:self mapView:self.mapView title:#"Layer Successfully Saved!" message:#"Choose the layers button in the navigation bar to access saved layers."];
[self saveOverlay];
}
I get the following output:
2018-02-05 13:47:12.387032-0800 prism[4910:1739598] Model ====> <DrawnLayerModel: 0x1c424d2c0>
2018-02-05 13:47:12.387166-0800 prism[4910:1739598] Title ====> Blue.
2018-02-05 13:47:12.387204-0800 prism[4910:1739598] Model ====> <DrawnLayerModel: 0x1c424d2c0>
2018-02-05 13:47:12.387235-0800 prism[4910:1739598] Title ====> Blue.
Now if you look at the DrawnLayerModel output these numbers are suspiciously the same:
0x1c424d2c0
Is that an address where the object was saved? Why are my properties being duplicated?
Once I add multiple models to my array
The problem is with the code that does that:
DrawnLayerModel *model = [self.drawnLayerModel initWithOverlay:self.mapView.overlays.lastObject fillColor:self.customFillColor lineColor:self.customLineColor overlayTitle:self.layerName];
[self.overlaysArray addObject:model];
You are just reinitializing the same persistent object over and over (self.drawnLayerModel). Thus, you are adding the same object to the array twice (or more). Adding an object to an array doesn't copy it, and an object pointer is merely a reference, so you are able to add multiple references to one object to an array.
The real problem here is that you have broken the most basic law of instantiation in Objective-C: Never say init without having said alloc in the very same set of square brackets. And vice versa: never say alloc without saying init in the same line.

add new object to nsmutablearray replace all objects in array

i try to add new object to my nsmutablearray but every time it replace all object
-(void)addToStack:(Coordinate *)coord{
Coordinate*c = [[Coordinate alloc] init];
c.x=coord.x;
c.y = coord.y;
if (coord.x==0 && coord.y==0) {
c.x=coord.x+1;
[_stack addObject:c];
c.x=coord.x;
c.y=coord.y+1;
[_stack addObject:c];
c.y=coord.y;
}
}
You are not adding a new object but you are changing the old object where the reference will remain the same.
NSMutableArray addObject will not add it because it already exists in the array.
So, when trying to add a new object, first create a copy of the one that you want to change, like this:
Coordinate *newCoordinate = [Coordinate mutableCopy];
// change attributes
// add it to the array
Everybody who said that adding the same object twice deletes the first instance and replaces it, is wrong.
Arrays can contain duplicate references to the same object. However, it's more like saving the same street address in an rolodex twice. If you look up the address in the first entry, go break all the windows in that house, then go back, look up the address in the second slot in your rolodex, and drive to THAT address, you'll find the house has broken windows (Because both addresses point to the same house.)
Similarly, when you add the same object to an array twice, it's two pointers to the same object. When you change values of the object at index 0, you see those changes reflected in the object in index 1 because it's a second pointer to the same object.
Despite saying the wrong thing about what goes wrong with your code, #Shashi3456643 gave you the correct solution, which is to create a new, unique object for every entry in your array.
Make sure to initiate the array:
NSMutableArray *stack=[[NSMutableArray alloc] init];
This is because every time you init the array. Initialize the array once.
For example:
in .h
Coordinate*c;
in .m
- (void)viewDidLoad
{
c = [[Coordinate alloc] init];
}
-(void)addToStack:(Coordinate *)coord{
c.x=coord.x;
c.y = coord.y;
if (coord.x==0 && coord.y==0) {
c.x=coord.x+1;
[_stack addObject:c];
c.x=coord.x;
c.y=coord.y+1;
[_stack addObject:c];
c.y=coord.y;
}
}

Iterating through two arrays

I have an iOS app that I load data from a server into an NSArray and then into UITableView.
This works fine. However, when the user pulls down to refresh the data, I make a new call to my server and grab data again. This new data contains objects that my local data already has and any new objects.
So localArray when populated for the first time will have objects, [A,B,C,D]. I then add a new object server side and refresh the data on the iOS app.
serverData will now have objects [A,B,C,D,E,F] - I need to add, E,F to localArray.
I thought a nested for loop would be the answer, something like this:
NSMutableArray *newItems = [NSMutableArray array];
for (BBItem *itemA in serverDataArray){
for (BBItem *itemB in localArray){
if (![itemA.name isEqualToString:itemb.named]){
//add to a newItems array
}
}
}
However I end up with newItems array containing a lot of duplicates of the same item. What is going on here?
Your algorithm will add an item to newItems if it's not equal to one item from localArray. Therefore, you would end up with lots of identical items most of the time.
You cannot add inside the nested loop. You need to go through all localArray, see that the item is not there, and only then add it. Here is how to fix your code:
for (BBItem *itemA in serverDataArray){
BOOL there = NO;
for (BBItem *itemB in localArray){
if ([itemA.name isEqualToString:itemb.named]){
there = YES;
break;
}
}
if (!there) {
//add to a newItems array
}
}
This is inefficient, because the inner loop goes through all items that you currently have. As the number of local items grows, this loop will get slower and slower. You would be better off maintaining an NSMutableSet of names of local items, because you can check it in constant, rather than in linear, time:
NSMutableSet *localNames = [NSMutableSet set];
for (BBItem *itemB in localArray) {
[localNames addObject:itemB.name];
}
for (BBItem *itemA in serverDataArray){
if (![localNames containsObject:itemA.name]) {
//add to a newItems array
}
}

Delete Sync between searchResultsTableView and mainTableView

I have a simple question and I am looking for most efficient way to deal with this.
I have a main table (say mainTableView) and it has search bar controlled by searchResultsTableView.
My main table has a mutable array say mainItems of say 10 items.
When search is performed, the searchResultsTableView may contain say 3 items in different mutable array say searchedItems
now in that search controller I deleted 2 out of 3 items and I also delete from searchedItems and searchResultsTableView. These are delete 1 at a time.
So as I delete from searchedItems I also needs to delete from mainItems to keep in sync but the index would keep changing for every delete in mainItems so how do I know the original index to be deleted in mainItems?
Should I look for some dictionary based approach instead of array?
Cant you compare the objects inside array and remove using index.
Say like this, if the item deleted from searchedItems is deletedObj
int indexToDelete = -1;
for(i=0; i<[mainItems length]; i++){
Object * myMainObj = mainItems[i];
if (myMainObj isEqual:deletedObj) //this will work depends on the object inside your datasource
{
indexToDelete = i;
break;
}
}
if(indexToDelete != -1){
[mainItems removeObjectAtIndex:indexToDelete];
}

NSMutableArray replacing object insted of adding

I'm using a NSMutableArray to store an object called poligonon. This object has a NSMutableArray as property to store coordinates X.
But when I add the second object, the first object on the array transform itself. All objects on the array must be differents, but they are equal the last object in the array.
Exemple:
coordArrayX is a property (NSMutableArray)
-saveDataIntoArray
{
poligonon.coorArrayX = coordArrayX;
arrayPoligonon addObject: poligonon;
}
The first time that the user clicks to save, the first coordinate is 74.
Now, he creates a new poligonon that has coordinate 45, and add to the array.
When the user checks, the first poligonon has coordinate = 45.
How to solve?
Each and every time you are adding the same poligonon to the array and overwriting the value of coorArrayX.
Instead of,
{
poligonon.coorArrayX = coordArrayX;
arrayPoligonon addObject: poligonon;
}
Try this,
{
poligonon = [[Poligonon alloc] init];
poligonon.coorArrayX = coordArrayX;
[arrayPoligonon addObject:poligonon];
}

Resources