How to Modify UITableView Data Source Array Properly - objective-c

Say I would like to remove rows or add rows to a table. Is it smarter for me to modify the data source and let the table do updates or use UITableView's insertRowsAtIndexPaths:withAnimation: and deleteRowsAtIndexPaths:withAnimation: selectors? Whenever I try to modify the actual data source array, whose size is also used to determine in the the data source's tableView:numberOfCellsInSection: protocol method, I am thrown an error saying that the table must have the same number of cells per section before and after a table update. The data source array itself is an NSMutableArray; does this array get automatically updated when I use the deleteRowsAtIndexPaths and insertRowsAtIndexPaths selectors? I would assume not. But how do I add or remove rows while also updating the data source array?

Yes.
NSMutableArray* array = #["a", "b", "c"]
NSLog(#"%#", array[1])
// prints "b"
[array removeObjectAtIndex:1]
// ["a", "c"]
NSLog(#"%#", array[1])
// now prints "c".

Related

dispatch_async doesn't go into loop

I need to fill in array. I have two methods. First of this create object that need to be added to array. I do it like this:
__block NSMutableArray *array = [[NSMutableArray alloc] initWithCapacity:inputArray.count];
dispatch_queue_t queue =dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_sync(queue, ^{
dispatch_apply(inputArray.count,queue , ^(size_t index) {
[array insertObject:[self getObject:[inputArray objectAtIndex:index]] atIndex:index];
});
});
Finally I receive array with 2 objects instead of 100. I need to get array with objects that processed in getObject function.
If i code this:
dispatch_apply(inputArray.count, queue, ^(size_t index){
[array insertObject:[self getObject:[inputArray objectAtIndex:index]] atIndex:index];
});
I receive different numbers of array count. Can anybody tell me how to do it correctly?
The method initWithCapacity does not create an array with that many elements, it is just a hint to NSMutableArray on what the number of elements is likely to be. When you then try to insert an object at a specific instances things go wrong. From the docs for insertObject:atIndex::
Note that NSArray objects are not like C arrays. That is, even though you specify a size when you create an array, the specified size is regarded as a “hint”; the actual size of the array is still 0. This means that you cannot insert an object at an index greater than the current count of an array. For example, if an array contains two objects, its size is 2, so you can add objects at indices 0, 1, or 2. Index 3 is illegal and out of bounds; if you try to add an object at index 3 (when the size of the array is 2), NSMutableArray raises an exception.
You'll get different behaviour depending on the order the blocks queued by dispatch_apply are executed.
I'm assuming you are doing this as your getObject: is a time consuming process but multiple of them may be performed in parallel. If that is the case then:
a) After allocating the array pre-fill it up with cheap objects, e.g. [NSNull null] will do.
b) Use replaceObjectAtIndex:withObject: to add your objects to the array, this will replace your pre-filled object with your real ones.
Note: You are also misusing __block. This attribute is for when you wish to change the value of a local variable in the enclosing method from within a block. You never change the value of array either in the method or the block after you assign a reference to an NSMutableArray instance to it when it is declared. Your code then modifies the contents of the referenced object, not the value of the reference. Remove the __block.
HTH

xcode > reorganise Mutable array values

I am new to Xcode and i have created a NSmutableArray that retrieves its values from a function. i would like to able to re organise the contents of my Array
When i output my array, i get the following results
(value A,value B,value C,value D)
I would like to re organize my array to appear a customised way so i would like it to appear in the following way
(value B,value D,value A,value C)
Any ideas on how to acheve this ?
I am using xcode 4.6.2
User can see the custom order and sorted order. right?
Have a NSMutableArray. Organise the content and Iterate to show it in UITableview
When you want to show sorted content in UITableView use the below method to get the sorted array.
-(NSMutableArray *)mySortedArray
{
return [myArray sortedArrayUsingSelector:#selector(localizedCaseInsensitiveCompare:)];
}

How do you correctly get a row value from a table view?

I have implemented code that returns 0 every time. I'm trying to remove a string from a mutable array with the row value selected after hitting a button.
Related code:
- (IBAction)remove:(id)sender {
NSIndexPath *selectedIndexPath = [_tableView2 indexPathForSelectedRow];
[names removeObject:[NSString stringWithFormat:#"%i",selectedIndexPath.row]];
testLabel.text=[NSString stringWithFormat:#"%i",selectedIndexPath.row];
[_tableView2 reloadData];
}
The test label shows 0 every time the button is pressed, no matter where the tableview is selected.
Let me know if there is other relevant code (like the tableView) that you want me to post.
For a UITableView, the selected row concept is only valid while the user is touching the row. For that reason indexPathForSelectedRow is documented as returning “An index path identifying the row and section indexes of the selected row or nil if the index path is invalid.”
My opinion is that you are obtaining a nil result, and later calling the row method in that nil results in the zero that your are seeing as your name.
The solution depends on the rest of your data source implementation, but probably will involve storing the tapped index in didSelectRowAtIndexPath: to later use it in your remove method.
(I supposed that you are not using the allowsMultipleSelectionDuringEditing option nor are you editing the table).
Instead of:
[names removeObject:[NSString stringWithFormat:#"%i",selectedIndexPath.row]];
Try:
[name removeObjectAtIndex:selectedIndexPath.row];
Also, instead of using #"%i", try using #"%d" as mentioned here
Hope this helps!

Objective-C: How to get data from selected row in table?

I need to retrieve a string from data from a selected row in a table to compare it to a string.
I call
NSArray *values = [self.tableArrayController selectedObjects];
To get the objects at the selected row. However, values only has a count of objects of 1, and everything seems to be one big, long string of all my values. I cannot search through the values because I won't always know what to search for. I need a specific value (of which they are organized by columns).
I was hoping that the array would be of a certain count and I could retrieve the string based on the index of the object for the string.
How should I get all the different values (organized by columns) for a selected row?
EDIT:
I populate a NSDictionary (withmore values than that, this is just an example). The string value is the column identifier. The object is the object I'm adding that I want to appear on the table. This part below already works as I want it to:
NSDictionary *dict =[NSDictionary dictionaryWithObjectsAndKeys:
object1, #"column",
object2, #"column2",
nil];
[self.tableArrayController addObject:dict];
Another way to get data from your table is to look at the "NSTableView" methods "selectedRow" & "selectedColumn".
With that information, you can get at the value you want directly via your array controller or you can use the NSTableViewDataSource method "tableView:objectValueForTableColumn:row:" to pass you back the NSString value of whatever it is that you're trying to get at.

Animating NSTableView with beginning and ending array states

I've been looking over NSTableView's moveRowAtIndex:toIndex method for animating rows in a table. It's not really helpful for sorting though from what I can tell. My interpretation of how it works is, if I want to move row 0 to row 4, then the rows in between are handled appropriately. However, if I have a table view with an array backing it, and then I sort the array, I want the table view to animate from the old state to the new state. I don't know which items were the ones that moved vs the ones that shift to accommodate the moved ones.
Example:
[A,B,C,D] --> [B,C,D,A]
I know that row 0 moved to row 3 so I would say [tableView moveRowAtIndex:0 toIndex:3]. But if I apply some custom sort operation to [A,B,C,D] to make it look like [B,C,D,A], I don't actually know that row 0 moved to row 3 rather than rows 1,2, and 3 moving to rows 0,1, and 2. I would think that I should just be able to specify all of the movements (row 0 moved to row 4, row 1 moved to row 0, etc.) but the animation doesn't look correct when I try that.
Is there a better way to do this?
Edit: I found this site, which seems to do what I want but seems like a bit much for something that should be simple (at least I think it should be simple)
The documentation for moveRowAtIndex:toIndex: says, "Changes happen incrementally as they are sent to the table".
The significance of 'incrementally' can be best illustrated with the transformation from ABCDE to ECDAB.
If you just consider the initial and final indexes, it looks like:
E: 4->0
C: 2->1
D: 3->2
A: 0->3
B: 1->4
However, when performing the changes incrementally the 'initial' indexes can jump around as you transform your array:
E: 4->0 (array is now EABCD)
C: 3->1 (array is now ECABD)
D: 4->2 (array is now ECDAB)
A: 3->3 (array unchanged)
B: 4->4 (array unchanged)
Basically, you need to tell the NSTableView, step-by-step, which rows need to be moved in order to arrive at an array identical to your sorted array.
Here's a very simple implementation that takes an arbitrarily sorted array and 'replays' the moves required to transform the original array into the sorted array:
// 'backing' is an NSMutableArray used by your data-source
NSArray* sorted = [backing sortedHowYouIntend];
[sorted enumerateObjectsUsingBlock:^(id obj, NSUInteger insertionPoint, BOOL *stop) {
NSUInteger deletionPoint = [backing indexOfObject:obj];
// Don't bother if there's no actual move taking place
if (insertionPoint == deletionPoint) return;
// 'replay' this particular move on our backing array
[backing removeObjectAtIndex:deletionPoint];
[backing insertObject:obj atIndex:insertionPoint];
// Now we tell the tableview to move the row
[tableView moveRowAtIndex:deletionPoint toIndex:insertionPoint];
}];