What I am trying to achieve:
I have a UITableView and I want to check whether the table was selected or not and keep in an array easy to access the YES or NO values that corresponds to that row so that afterwards i can manipulate the data.
my code as follows
- (void) tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
NSUInteger row = [indexPath row];
UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
NSString *cellLabelText = cell.textLabel.text;
if (cell.accessoryType == UITableViewCellAccessoryCheckmark) {
cell.accessoryType = UITableViewCellAccessoryNone;
selected[row] = NO;
}
else {
cell.accessoryType = UITableViewCellAccessoryCheckmark;
selected[row] = YES;
}
}
As it stands out I can create a BOOL selected[some value] but my problem is that the max index needed for me is unknown as my table size changes constantly. thus setting the max index limits me.
I am new to objective C and I come from a PHP background thus I dont know whether it is possible to create an array that does what i want to do in objective-c.
Otherwise what would be my options within objective-c to have an easy way to easy write/read selected[row] = YES/NO.
I need a way to write YES/NO and link it to the indexpath.row
Use an NSMutableSet and store the NSIndexPath of the selected rows. If you select a row you add the path to the set. If you unselect a row, remove the path from the set.
To see if a row is selected, see if the indexPath is in the set or not.
BTW - this only works if the rows are fixed. If the user can add, remove, or reorder rows then this approach will not work. In such a case you need to store data keys, not index paths.
Create an ivar of type NSMutableSet. Let's call it selectedRows:
selectedRows = [[NSMutableSet alloc] init];
Then in didSelectRow you do:
- (void) tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
BOOL selected = [selectedRows containsObject:indexPath];
UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
NSString *cellLabelText = cell.textLabel.text;
if (selected) {
cell.accessoryType = UITableViewCellAccessoryNone;
[selectedRows removeObject:indexPath];
} else {
cell.accessoryType = UITableViewCellAccessoryCheckmark;
[selectedRows addObject:indexPath];
}
}
In your cellForRow... method you do something similar:
BOOL selected = [selectedRows containsObject:indexPath];
cell.accessoryType = selected ? UITableViewCellAccessoryCheckmark : UITableViewCellAccessoryNone;
Just use
NSMutableArray *dynamicArray = [NSMutableArray array];
You can add and delete objects from this at will. Just be sure to use the NSNumber wrapper to add primitives:
[dynamicArray addObject:[NSNumber numberWithInt:indexNumber]];
// or
[dynamicArray addObject:#(indexNumber)];
Instead of an array you can use a index set.
#property (nonatomic,strong) NSMutableIndexSet *pickedIndexPaths;
- (void)viewDidLoad
{
_pickedSIndexPaths = [[NSMutableIndexSet alloc] init];
[super viewDidLoad];
}
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
//…
if(indexPath.section == 0) {
cell.textLabel.text = self.sports[indexPath.row][#"sport"][#"name"];
if ([_pickedIndexPaths containsIndex:indexPath.row]) {
[cell setAccessoryType:UITableViewCellAccessoryCheckmark];
} else {
[cell setAccessoryType:UITableViewCellAccessoryNone];
}
}
return cell;
}
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
if ([_pickedIndexPaths containsIndex:indexPath.row]) {
[_pickedIndexPaths removeIndex:indexPath.row];
} else {
[_pickedIndexPaths addIndex:indexPath.row];
}
[tableView reloadData];
}
}
When what you need is a variable length array of boolean values, you can use CFBitVectorRef. This will consume much less memory than using a Cocoa collection designed for objc object values (provided of course that array has many elements) because it consumes 1 bit for each value, rather than a full pointer which points to an individual dynamically allocated reference counted object.
Related
Here i need to implement add objects into array for multiple row selections,here is my code
BOOL selectedRow
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath: (NSIndexPath *)indexPath{
if(selectedRow){
UITableViewCell *selectedCell = [tableView cellForRowAtIndexPath:indexPath];
cellText = selectedCell.textLabel.text;
NSLog(#"Airline cellTextC = %#",cellText);
if ([cellText isEqualToString:NameString]) {
NSLog(#"Selected NameString Index = %#",indexes);
[nameArray addObject:indexes];
}else{
NSLog(#"Unknown Selected Name");
}
}
NSLog(#"Total Names = %#",nameArray.description);
}
the above code one section and multiple rows is there ,if am selected a row name string should be add to the Array .It's working fine for only while am selecting one row.But i need add objects from multiple row selections.Can you please suggest me thanks .
You probably want to update the data source of the Table View, and let the Table View Data source methods to update the Table View for you.
Check if this can solve your problem:
[tableView setAllowsMultipleSelection:YES];
if you want to select Multiple rows and add objects to your array i suggest to create 2 NSMutableArray the first one contains all data and the other the selected rows data.
#property (strong , nonatomic) NSMutableArray *myalldatatab;
#property (strong , nonatomic) NSMutableArray *selecteddata;
then use didselectrowsatindexpath and didDeselectRowAtIndexPath to change the mark
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
[tableView cellForRowAtIndexPath:indexPath].accessoryType = UITableViewCellAccessoryCheckmark;
}
- (void)tableView:(UITableView *)tableView didDeselectRowAtIndexPath:(NSIndexPath *)indexPath {
[tableView cellForRowAtIndexPath:indexPath].accessoryType = UITableViewCellAccessoryNone;
}
and you can get indexes of selected rows by calling this line :
NSArray *selectedCells = [self.tableView indexPathsForSelectedRows];
you can now iterate selected cells and add objects like this
for (int i = 0; i < [selectedCells count]; i++)
{
[self.selecteddata addObject: [selectedCells objectAtIndex:i]]
}
Hope it help you :)) happy c0de !!
hey i have created a table view with multiple selection and checkmark accessory which users can tap on and select relevant rows in table... retailerid and retailernaem of individual selection will be stored in NSMutableDictionary and all dictionaries in return will be stored in NSMutableArray... i have done this till now
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *selectedCell = [tableView cellForRowAtIndexPath:indexPath];
if ([selectedCell accessoryType] == UITableViewCellAccessoryNone) {
[selectedCell setAccessoryType:UITableViewCellAccessoryCheckmark];
NSMutableDictionary *theDictionary = [[NSMutableDictionary alloc] init];
[theDictionary setObject:[[BrandsArray valueForKey:#"RetailerID"] objectAtIndex:indexPath.row] forKey:#"id"];
[theDictionary setObject:[[BrandsArray valueForKey:#"RetailerName"] objectAtIndex:indexPath.row] forKey:#"name"];
[selectedIndexes addObject:theDictionary];
}
else {
[selectedCell setAccessoryType:UITableViewCellAccessoryNone];
NSLog(#"this is deselected row %#",[selectedIndexes objectAtIndex:indexPath.row]);
NSMutableDictionary *dictionary = [selectedIndexes objectAtIndex:indexPath.row];
[selectedIndexes removeObject:dictionary];
dictionary = nil;
}
[tableView deselectRowAtIndexPath:indexPath animated:NO];
}
now problem is in the else block... its not removing objects from randomly selected row...
for example if i select first row and then deselect the same it works fine but when i select the last row and then deselect the same app crash..
Since my other answer dealt with multiple sections, I will provide a simpler, single section answer here
First, declare a property for your selection state -
#property (strong,nonatomic) NSMutableIndexSet *selectStates;
Initialise it in viewDidLoad
self.selectStates=[NSMutableIndexSet new];
The use it in didSelectRowAtIndexPath -
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *selectedCell = [tableView cellForRowAtIndexPath:indexPath];
if ([self.selectStates containsIndex:[indexPath.row]) {
[selectedCell setAccessoryType:UITableViewCellAccessoryNone];
[self.selectStates removeIndex:indexPath.row];
} else {
[selectedCell setAccessoryType:UITableViewCellAccessoryCheckmark];
[self.selectStates addIndex:indexPath.row];
}
[tableView deselectRowAtIndexPath:indexPath animated:NO];
}
You will also need to check the selectedStates in cellForRowAtIndexPath to set the correct accessory when the cell is scrolled back into view. Just add the snippet -
if ([self.selectStates containsIndex:[indexPath.row]) {
[cell setAccessoryType:UITableViewCellAccessoryNone];
} else {
[cell setAccessoryType:UITableViewCellAccessoryCheckmark];
}
If you need the ability to easily insert and delete rows then you can use an NSMutableSet instead of an NSIndexSet - just store the data source object. If you do allow deletion you need to make sure that the object is removed from the set, if necessary, when the row is deleted.
First, declare a property for your selection state -
#property (strong,nonatomic) NSMutableSet *selectStates;
Initialise it in viewDidLoad
self.selectStates=[NSMutableSet new];
The use it in didSelectRowAtIndexPath -
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *selectedCell = [tableView cellForRowAtIndexPath:indexPath];
Brand *brand=(Brand *)[BrandsArray objectAtIndex:indexPath.row]; // Change "Brand" to the appropriate object class
if ([self.selectStates containsObject:brand) {
[selectedCell setAccessoryType:UITableViewCellAccessoryNone];
[self.selectStates removeObject:brand];
} else {
[selectedCell setAccessoryType:UITableViewCellAccessoryCheckmark];
[self.selectStates addObject:brand];
}
[tableView deselectRowAtIndexPath:indexPath animated:NO];
}
You will also need to check the selectedStates in cellForRowAtIndexPath to set the correct accessory when the cell is scrolled back into view. Just add the snippet -
if ([self.selectStates containsObject:brand) {
[cell setAccessoryType:UITableViewCellAccessoryNone];
} else {
[cell setAccessoryType:UITableViewCellAccessoryCheckmark];
}
The problem is the way you use the array.
Let's say you select the last element from a table view with 10 cells. Then the array size is 1, but when you select again the last row, [selectedIndexes objectAtIndex:indexPath.row]; is trying to access the element with index 9 in the array, which does not exist at the moment.
Try to implement something like this:
NSInteger ARRAY_INITIAL_SIZE = 100;
NSMutableArray *selectedIndexes = [NSMutableArray arrayWithCapacity:ARRAY_INITIAL_SIZE];
for (NSInteger i = 0; i < ARRAY_INITIAL_SIZE; ++i) {
selectedIndexes[i] = [NSNull null];
}
Make selectedIndexes to be a property in your View Controller class, and whenever you use it, put self.selectedIndexes instead.
In the didSelectRow: atIndexPath: method, the first line is recommended to be:
[tableView deselectRowAtIndexPath:indexPath animated:NO];
Then, write the code:
UITableViewCell *selectedCell = [tableView cellForRowAtIndexPath:indexPath];
if ([selectedCell accessoryType] == UITableViewCellAccessoryNone) {
selectedCell.accessoryType = UITableViewCellAccessoryCheckmark;
NSMutableDictionary *theDictionary = [NSMutableDictionary dictionary];
[theDictionary setObject:[[BrandsArray valueForKey:#"RetailerID"] objectAtIndex:indexPath.row] forKey:#"id"];
[theDictionary setObject:[[BrandsArray valueForKey:#"RetailerName"] objectAtIndex:indexPath.row] forKey:#"name"];
[selectedIndexes replaceObjectAtIndex:indexPath.row withObject:theDictionary];
} else {
selectedCell.accessoryType = UITableViewCellAccessoryNone;
[selectedIndexes replaceObjectAtIndex:indexPath.row withObject:[NSNull null]];
}
I hope it helps you. Let me know.
I am new to iOS development, i've been following apple intro to iOS and implemented the to-do list app.
I have tableview that shows the list of the current to-do list, and another view controller that allows the user to add a new item in a textfield then add to the list.
I have a little + on top of my tableview that performs a segue action to the add to-do item view.
I want to be able to perform the same action if the user taps on an empty cell
I tried to put this code in and it works but I want to put it in the right position so it only triggers when the user hits empty space in the table:
[self performSegueWithIdentifier:#"showAddItem" sender:self];
Thank you.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *cellIdentifier = #"ListPrototypeCell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier forIndexPath:indexPath];
// Configure the cell...
ABCTodoItem *toDoItem = [self.toDoItems objectAtIndex:indexPath.row];
cell.textLabel.text = toDoItem.itemName;
if (toDoItem.completed) {
cell.accessoryType = UITableViewCellAccessoryCheckmark;
}
else
{
cell.accessoryType = UITableViewCellAccessoryNone;
}
return cell;
}
In my opinion this solution is the cleanest:
Add a tap gesture to your UITableView's backgroundView. If the backgroundView is nil, add a transparent UIView, and add a gesture to it.
Now hook up your action to this gesture recognizer.
I can see at least two solutions here.
Solution 1. Adding en empty cell by modifying the data source
After you have populated your toDoItems add this:
[self.toDoItems addObject:#""];
Notice that toDoItems should be type of NSMutableArray.
Now let's handle creating cells:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *cellIdentifier = #"ListPrototypeCell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier forIndexPath:indexPath];
NSObject *objItem = [self.toDoItems objectAtIndex:indexPath.row];
if([objItem isKindOfClass: [ABCTodoItem class]]) {
ABCTodoItem *toDoItem = (ABCTodoItem*) objItem;
cell.textLabel.text = toDoItem.itemName;
}
else if([objItem isKindOfClass: [NSString class]]) {
NSString *item = (NSString*) objItem;
cell.textLabel.text = item;
}
return cell;
}
Touch action:
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
NSObject *objItem = [self.toDoItems objectAtIndex:indexPath.row];
if([objItem isKindOfClass: [ABCTodoItem class]]) {
ABCTodoItem *toDoItem = (ABCTodoItem*) objItem;
// Open your toDoItem
}
else if([objItem isKindOfClass: [NSString class]]) {
self performSegueWithIdentifier:#"showAddItem" sender:self];
}
}
Solution 2. Adding an empty cell without modifying the data source
This makes it possible to create one extra cell:
- (NSInteger)numberOfRowsInSection:(NSInteger)section {
return [self.toDoItems count] + 1;
}
Now again let's handle creating cells:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *cellIdentifier = #"ListPrototypeCell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier forIndexPath:indexPath];
if([indexPath.row < [self.toDoItems count]) {
NSObject *objItem = [self.toDoItems objectAtIndex:indexPath.row];
if([objItem isKindOfClass: [ABCTodoItem class]]) {
ABCTodoItem *toDoItem = (ABCTodoItem*) objItem;
cell.textLabel.text = toDoItem.itemName;
}
}
else {
cell.textLabel.text = #"";
}
return cell;
}
And then handling the touch action:
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
if([indexPath.row < [self.toDoItems count]) {
NSObject *objItem = [self.toDoItems objectAtIndex:indexPath.row];
if([objItem isKindOfClass: [ABCTodoItem class]]) {
ABCTodoItem *toDoItem = (ABCTodoItem*) objItem;
// Open your toDoItem
}
}
else {
self performSegueWithIdentifier:#"showAddItem" sender:self];
}
}
I hope I have understood your question correctly; correct me if I am wrong. You have a to-do List populated in a TableViewController which has some tasks and one (or more) empty cells. When you click on these cells, you would want to call [self performSegueWithIdentifier:#"showAddItem" sender:self]; a method that presents a ViewController that allows you to add more items into the list.
Once you have populated your TableViewController in such a way that you have an empty cell, you can always get the NSIndexPath of the empty cell.
When you tap on a cell, a method will be called, called: (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath. As you can see, you will get the index information of the tapped cell. There, you can add the code like so:
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
//Add your logic for the rest of the items
//If you have 7 items in the to-do list, you would have 8 cell,
//the eight one being empty. If indexPath.row is equal to 8 then,
//it says that it MUST be the last item, that is empty
if(indexPath.row == self.itemsInTheList.count) {
[self performSegueWithIdentifier:#"showAddItem" sender:self];
}
}
Alternatively, you can set the tag property of the cell; and that's the story for a different day.
My cell.textLabel.text sometimes returns an empty string. Is there a way I can skip this cell and put my next text label right after my last non empty cell.textLabel.text? So there should no empty labels.
- (UITableViewCell *)tableView:(UITableView *)tableView
cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *MyIdentifier = #"MyIdentifier";
UITableViewCell *cell = [self.tableView dequeueReusableCellWithIdentifier:MyIdentifier];
if (cell == nil)
{
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault
reuseIdentifier:MyIdentifier];
}
ResultModel *resultModel = [self.array objectAtIndex:indexPath.row];
cell.textLabel.text = resultModel.resultString;
return cell;
}
cell.textLabel takes the whole content view's size.width so you calculate the length of the string and manipulate next label accordingly
Try this code.
if([resultModel.resultString isEqualToString:#""])
{
// Display the label
cell.textLabel.text = resultModel.resultString;
}
else
{
//result string is Null do nothing here.
}
Why don't you just get instances which have value in "resultString" property?
NSArray *dataWithResultString = [call the custom method to get instances with no empty value];
ResultModel *resultModel = [dataWithResultString objectAtIndex:indexPath.row];
This you should handle in the datasource array itself...
Populate a new array with values having the resultModel.resultString and use this array as the datasource for tables
if i understand you correctly you want the cell to be displayed only if there is some non empty string in resultModel.resultString, right?
For that you better handle the datasource array itself. If that's hard, you can do this.
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath{
ResultModel *resultModel = [self.array objectAtIndex:indexPath.row];
if([resultModel.resultString isEqualToString:#""])
return 0.0;
else
return 50;//or whatever
}
But its better handling the datasource itself.
If I'm reading you right, the resulted array might return an empty string and if so, you don't want to show those rows right?
Ideally, you should've add another parameter to your query to exclude the empty resultString. However, if you want a hacky way, declare (int)padRows and set it to 0 in viewDidLoad;
- (UITableViewCell *)tableView:(UITableView *)tableView
cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *MyIdentifier = #"MyIdentifier";
UITableViewCell *cell = [self.tableView dequeueReusableCellWithIdentifier:MyIdentifier];
if (cell == nil)
{
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault
reuseIdentifier:MyIdentifier];
}
ResultModel *resultModel = [self.array objectAtIndex:indexPath.row];
while([resultModel.resultString isEqualToString:#""]) {
_padRows += 1;
resultModel = [self.array objectAtIndex:(indexPath.row+_padRows)];
}
cell.textLabel.text = resultModel.resultString;
return cell;
}
Code not tested.
All I'm looking to do is get the selected (checkmarked) rows from my UITableView and show them in my console log. Doesn't seem like it should be so difficult. I've found two methods that I'll display below. Neither work despite the logic mostly making sense to me. Which would you suggest and how can I tweak to make it work?
My TableView Code:
I don't think this is completely necessary to the issue, but I know it sometimes helps to see the whole picture.
#pragma mark - tableView datasource
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
// Return the number of sections.
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
// Return the number of rows in the section.
return [self.places count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
NSDictionary *tempDictionary= [self.places objectAtIndex:indexPath.row];
cell.textLabel.text = [tempDictionary objectForKey:#"name"];
if([tempDictionary objectForKey:#"vicinity"] != NULL)
{
cell.detailTextLabel.text = [NSString stringWithFormat:#"%#",[tempDictionary objectForKey:#"vicinity"]];
}
else
{
cell.detailTextLabel.text = [NSString stringWithFormat:#"Address Not Available"];
}
return cell;
}
//Handles tableView row selection and addition and removal of the checkmark
- (void)tableView:(UITableView *)theTableView
didSelectRowAtIndexPath:(NSIndexPath *)newIndexPath {
[theTableView deselectRowAtIndexPath:[theTableView indexPathForSelectedRow] animated:NO];
UITableViewCell *cell = [theTableView cellForRowAtIndexPath:newIndexPath];
if (cell.accessoryType == UITableViewCellAccessoryNone) {
cell.accessoryType = UITableViewCellAccessoryCheckmark;
// Reflect selection in data model
} else if (cell.accessoryType == UITableViewCellAccessoryCheckmark) {
cell.accessoryType = UITableViewCellAccessoryNone;
// Reflect deselection in data model
}
}
Method 1:
Add a conditional statement to the end of the checkmark handler to add/remove selections to and from an array. Then create a button action that simply calls the array and displays it in the console. I think this is clunky but could work.
//Handles tableView row selection and addition and removal of the checkmark
- (void)tableView:(UITableView *)theTableView
didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
[theTableView deselectRowAtIndexPath:[theTableView indexPathForSelectedRow] animated:NO];
UITableViewCell *cell = [theTableView cellForRowAtIndexPath:indexPath];
if (cell.accessoryType == UITableViewCellAccessoryNone) {
cell.accessoryType = UITableViewCellAccessoryCheckmark;
//Reflect selection in data model
} else if (cell.accessoryType == UITableViewCellAccessoryCheckmark) {
cell.accessoryType = UITableViewCellAccessoryNone;
//Reflect deselection in data model
}
if ([[theTableView cellForRowAtIndexPath:indexPath] accessoryType] == UITableViewCellAccessoryCheckmark) {
[_selectedCellIndexes addObject:indexPath];
}
}
- (IBAction)sendResults:(id)sender {
NSLog(#"Add these: %#", _selectedCellIndexes);
}
Method 2:
Get the selected rows AND send to console log only when button is tapped. This seems to be the more logical method, but I can't seem to get it to work either. It doesn't throw any errors, but returns "Selected Items: (null)" in the console. What have I missed?
//Sends checkmarked items to console log
- (IBAction)sendResultsOption1:(id)sender {
NSMutableArray *aList = [[NSMutableArray alloc] init];
for (NSIndexPath *indexPath in _tableView.indexPathsForSelectedRows) {
NSString *r = [NSString stringWithFormat:#"%li",(long)indexPath.row];
[aList addObject:r];
}
NSLog(#"Selected Items: %#", _aList);
}
For what it's worth, I've also followed the instructions here without any luck. Hope you guys can help. Thanks in advance!
In Method 1, your method looks like this:
- (void)tableView:(UITableView *)theTableView
didSelectRowAtIndexPath:(NSIndexPath *)newIndexPath {
But you're referring to indexPath in the body. You don't have an indexPath (the undeclared identifier), but you have a newIndexPath, so at a minimum, this is the start of your problems and should be fixed first.
Giving your variables the right names looks like it should work for this approach...
In Method 2, the problem is none of your table view cells are selected. In you didSelectRowAtIndexPath method, you check the accessory icon to a check mark, then you deselect the row. So there are no objects in _tableView.indexPathsForSelectedRows.
In this approach, you need to change your for loop. Instead you need to iterate through every index path, and check on the accessory icon. If it's a check mark, add it to the array. Now log the array.
As far as which approach would be preferable, it depends on how you intend to use this ultimately. Obviously, the end goal isn't to NSLog the checkmarked rows--this is an iOS app we're talking about.