iOS Code Not Running When Method Called From Other Class - ios

I have a custom UITableViewCell xib that has two buttons on it. An edit button, designed to pass the info for that cell into a new view controller is the one I am currently having issues with. I create a property for the TableViewController in my custom cell, and hook up the button to this code:
-(IBAction) editItem {
self.itemsList = [[TheItemsList alloc] init];
[self.itemsList editItem];
NSLog(#"EDIT");
}
Inside TheItemsList I have this code:
-(void)editItem {
NSLog(#"EDITAGAIN");
EditItem *detailViewController = [[EditItem alloc] initWithNibName:#"EditItem" bundle:nil];
detailViewController.selectedCountry = self.selectedCountry;
NSIndexPath *indexPath = [self.tableView indexPathForSelectedRow];
detailViewController.therow = indexPath.row;
//Pass the selected object to the new view controller.
// Push the view controller.
[self.navigationController pushViewController:detailViewController animated:YES];
}
The console prints my NSLog for each method, but the view does not push. This code was previously used in the didSelectForIndexPath part of the table view, so I know that the view controller it is pushing is fine, I just can't figure out what is going on here.
UPDATE:
I have it SOMEWHAT working, emphasis on the somewhat.
ItemCell.h
#import <UIKit/UIKit.h>
#import "TheItemsList.h"
#class TheItemsList;
#class ItemCell;
#protocol ItemCellDelegate <NSObject>
#required
-(void)editTheItem:(ItemCell *)theCell;
#end
#interface ItemCell : UITableViewCell
#property (assign) id <ItemCellDelegate> delegate;
#property (nonatomic, retain) IBOutlet UILabel *itemName;
#property (nonatomic, retain) IBOutlet UILabel *itemPrice;
#property (nonatomic, retain) IBOutlet UILabel *itemAisle;
#property (nonatomic, retain) IBOutlet UIImageView *thumbnail;
#property (nonatomic, retain) TheItemsList *itemsList;
#end
.m
#import "ItemCell.h"
#import "EditItem.h"
#implementation ItemCell
#synthesize itemName = _itemName;
#synthesize itemAisle = _itemAisle;
#synthesize itemPrice = _itemPrice;
#synthesize thumbnail = _thumbnail;
#synthesize itemsList, delegate;
- (void)awakeFromNib {
[super awakeFromNib];
// Initialization code
}
-(IBAction) editItem {
[self.delegate editTheItem:self];
}
#end
Now, in the TableView
.h
#import <UIKit/UIKit.h>
#import "ItemCell.h"
#class ItemCell;
#protocol ItemCellDelegate;
#interface TheItemsList : UITableViewController <ItemCellDelegate>
.m
-(void)editTheItem:(ItemCell *)theCell {
NSLog(#"EDITAGAIN");
EditItem *detailViewController = [[EditItem alloc] initWithNibName:#"EditItem" bundle:nil];
detailViewController.selectedCountry = self.selectedCountry;
NSIndexPath *indexPath = [self.tableView indexPathForSelectedRow];
detailViewController.therow = indexPath.row;
//Pass the selected object to the new view controller.
// Push the view controller.
[self.navigationController pushViewController:detailViewController animated:YES];
}
What I'm running into is two problems.
1, the first item in the tableview doesn't do anything when the button is pressed.
2, the other rows will run code, but it only does it for the first row's data.

You should use the delegate pattern inside your UITableViewCell to delegate the button press back to the UIViewController which contains the UITableView using the cell.
In cellForRowAt:IndexPath you then retrieve the cell and set its delegate like cell.delegate = self. In the view controller you implement the delegate and handle the action.
In the cell you setup a delegate variable (var delegate: MyCellDelegate?) and inside the editItem function you make a call to the delegate like self.delegate?.editItem()

Your issue is basically because of this line
NSIndexPath *indexPath = [self.tableView indexPathForSelectedRow];
On clicking the button on the cell, it does not select the row necessarily. The button takes the touch. A way to solve this would be to find the NSIndexPath of the cell in which the button is present and then do your operations with it. A way to do is to use the cell reference that is being supplied from the editAction delegate
-(void)editTheItem:(ItemCell *)theCell
Replace [self.tableView indexPathForSelectedRow] with [self.tableView indexPathForCell:theCell]

Related

The value get by delegate method is been clear?

In tableViewControllerA.h I declare a delegate ,and in tableViewControllerA.m I implement the method when click a cell of the tableView, A will pass the value to B, and execute the perfromSegueWithIdentifier to jump to tableViewControllB,in tableViewControllB.m the getting method is called, and I get the value, but after the viewDidLoad() method call, the value become nil. Please help me to solve the problem.By the way , the property of the value is strong,nonatomic.
DTZHomeTableViewController.h
#import <UIKit/UIKit.h>
#import "PassData.h"
#protocol PassDataDelegate
-(void)passData:(PassData*) dataToProgram;
#end
#interface DTZHomeTableViewController :
UITableViewController<UITableViewDelegate,UITableViewDataSource>
#property(assign,nonatomic) id<PassDataDelegate> dataDelegate;
#end
PassData is an user-defined class
DTZHomeTableViewController.m
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
ProgramTableViewController *programViewController=
[[ProgramTableViewController alloc]init];
self.dataDelegate=programViewController;;
PassData *jump=[[PassData alloc]init];
jump.livingStatus=YES;
jump.role=0;
jump.index=indexPath.row;
jump.curOnlineNum=305605;
[self.dataDelegate passData:jump];
[self performSegueWithIdentifier:#"showSelectedProgram" sender:self];
}
ProgramTableViewController.h
#import <UIKit/UIKit.h>
#import "DTZHomeTableViewController.h"
#interface ProgramTableViewController :
UITableViewController<PassDataDelegate,UITableViewDataSource,UITableViewDelegate>
#property(strong,nonatomic) PassData * dataFromHome;
#end
ProgramTableViewController.m
#implementation ProgramTableViewController
- (void)viewDidLoad {
[super viewDidLoad];
NSLog(#"view did load%#",self.dataFromHome); // log :null
}
- (void) passData:(PassData *)dataToProgram
{
self.dataFromHome=dataToProgram;
}
#end
Delegation isn't the proper way to pass data to a segued view controller. Instead, you want to pass the data in prepareForSegue:sender:
Remove the protocol and delegate.
Add properties to your ProgramTableViewController for the data you want to pass.
#property (nonatomic, assign) BOOL livingStatus;
#property (nonatomic, assign) NSInteger role;
#property (nonatomic, assign) NSInteger row;
#property (nonatomic, assign) NSInteger curOnlineNum;
In prepareForSegue:sender:, set the ProgramTableViewController's passed properties to the values associated with the selected row:
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)__unused sender
{
if ([[segue identifier] isEqualToString:#"showDetail"])
{
NSIndexPath *indexPath = [self.tableView indexPathForSelectedRow];
ProgramTableViewController *controller = (ProgramTableViewController *)[segue destinationViewController];
controller.livingStatus = YES;
controller.role = 0;
controller.row = indexPath.row;
controller.curOnlineNum = 305605;
}
}
You shouldn't allocate and init ProgramTableViewController in tableView:didSelectRowAtIndexPath:. Your segue will instantiate the destination view controller for you.
You don't even need to have a tableView:didSelectRowAtIndexPath: method. You can create a push segue from the tableViewCell to ProgramTableViewController, right within Storyboard. Give the segue an identifier (such as "showDetail"). Then in prepareForSegue, you assign the values, as I explained.
When you tap on that row, the segue will create a ProgramTableViewController, set the parameters, and present it for you.

How can I link a button in iOS to change an array for a list view?

Not sure if the above is even my question as I am basically new to using objective-c and iOS and not sure if that's the right wording but anyway...
Basically I have completed this tutorial https://www.youtube.com/watch?v=ITUI7fukRO8 for using a tableView with an array of data.
The substance of the program consists of a navcontroller, tableviewController and a viewController for the extra detail of the table data.
Currently I have a button (from another viewcontroller) that is linking to my tableView.
How would I go about setting up and IF statement in regards to the button pressed (-as I need to link other buttons from other controllers) so that if a specific button is pressed, the array that is displayed in the tableView is different.
I'm currently thinking of doing a bunch of if, then, else statements and just manually changing the detail of the arrays.
Is this the way to go??
Or should I just set up another table view for each of my buttons.
I have a set of .h and .m for the tableCell, tableCellController, and the ViewController.
That probably didn't make a whole lot of sense but if you somewhat understand help would be appreciated.
Cheers
Edit: As you can see my code is pretty 'all over the shop' at the moment. I haven't included the Cell View controllers as I don't think they have that much relevance with what I want to do at this stage.The buttonviewcontroller is just a normal UIViewController and both buttons are linked as 'Button1'class in the storyboard. They have been given tags 0 and 1 which I believe is in under the 'view' subheading in the storyboard. Please alert me if this is wrong and I am missing something really obvious but that was the only place I could find 'tag'. ARRRG Objective-c is frustrating when you don't the language at all./
Updated Code as 21/03.
ButtonViewController.M (this is where the buttons are)
#import <UIKit/UIKit.h>
#import "tableViewController.h"
#import "TableCell.h"
#interface ButtonViewController : UIViewController
-(IBAction) button_Clicked:(id)sender;
#property (strong, nonatomic) IBOutlet UIButton *Button1;
#end
ButtonViewController.m
#import "ButtonViewController.h"
#import "tableViewController.h"
#import "TableCell.h"
#interface ButtonViewController ()
#end
#implementation ButtonViewController
-(IBAction) button_Clicked:(id)sender
{
//something here that is going wrong
tableViewController *tableVC = [[tableViewController alloc]initWithNibName:#"tableViewController" bundle:nil];
if(_Button1.tag==0)
{
tableVC.buttonSelected = 0;
}
else if(_Button1.tag==1)
{
tableVC.buttonSelected = 1;
}
[self.navigationController pushViewController:tableVC animated:YES];
[tableVC.tableView reloadData];
#end
tableViewController.h
#import <UIKit/UIKit.h>
#interface tableViewController : UITableViewController
#property (nonatomic, assign) int buttonSelected;
#property (nonatomic, strong) NSArray *Title;
//#property (nonatomic, strong) NSMutableArray *Title;
#property (nonatomic, strong) NSArray *Description;
//#property (nonatomic, strong) NSMutableArray *Description;
//Not sure if Mutable or normal array
#end
tableViewController.m
#import "tableViewController.h"
#import "TableCell.h"
#import "DetailViewController.h"
#import "ButtonViewController.h"
#interface tableViewController ()
#end
#implementation tableViewController
- (id)initWithStyle:(UITableViewStyle)style
{
self = [super initWithStyle:style];
if (self) {
// Custom initialization
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
if(_buttonSelected == 0)
{
_Title = #[#"Hamstring Muscle Tear",#"Lower Back Pain"];
_Description = #[#"Blahahaha", #"blahahaha2",#"blalalala3"];
[self.tableView reloadData];
}
else if (_buttonSelected == 1)
{
_Title = #[#"1",#"2",#"3"];
_Description = #[#"dededdededde", #"deddedede2",#"blalalala3"];
[self.tableView reloadData];
}
#pragma mark - Table view data source
- (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 _Title.count;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath: (NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"TableCell";
TableCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
// Configure the cell...
int row = [indexPath row];
cell.TitleLabel.text = _Title[row];
cell.DescriptionLabel.text = _Description[row];
return cell;
}
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
if ([[segue identifier] isEqualToString:#"ShowDetails"]) {
DetailViewController *detailviewcontroller = [segue destinationViewController];
NSIndexPath *myIndexPath = [self.tableView indexPathForSelectedRow];
int row = [myIndexPath row];
detailviewcontroller.DetailModal = #[_Title[row],_Description[row]];
}
}
#end
Do a CTRL - drag in Storyboard to create a IBAction for the button.
In the IBAction method, get the data you want for your data arrays (Images, Title, Description ref the tutorial you linked). Then call:
[tableview reloadData]
This will repopulate the tableview.

UICollectionView:didSelectItemAtIndexPath: How to populate new view with data based on selection?

Here's the deal:
I have a UICollectionView which populates itself from an array of objects. I want to be able to tap one of the views representing an object in my UICollection view and be taken to a new view displaying details of the object I selected in the UICollectionView (like the selected object's ID for example).
Unfortunately, whatever I try to set is always null!
Here is the object:
#interface obj : NSObject
#property (nonatomic, strong) NSString *objId;
...
#property (nonatomic, strong) NSString *imageURL;
#end
Here is the main view controller:
#interface ViewController : UIViewController <UICollectionViewDelegate, UICollectionViewDataSource, UICollectionViewDelegateFlowLayout>
#property (weak, nonatomic) IBOutlet UICollectionView *badgesCollectionView;
#property (strong, nonatomic) NSArray *objArray;
...
#end
Here is the detail view:
#interface DetailViewController : UIViewController
#property (weak, nonatomic) IBOutlet UILabel *objId;
#end
Here is where I'm trying to populate the detail view (in my main ViewController.m)
// Implement action for object selection
- (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath{
DetailViewController *detailView = [[DetailViewController alloc] init];
detailView.objIdLabel.text = [[self.objArray objectAtIndex:indexPath.row] objId];
[self.navigationController pushViewController:detailView animated:YES];
NSLog(#"Object Selection: Report");
NSLog(#"Label Text : %#", detailView.objId.text);
NSLog(#"Id of object : %#", [[self.objArray objectAtIndex:indexPath.row] objId]);
}
When I select an object in UICollectionView, I get a transition to a detailView without anything populated. Here is what's logged:
Object Selection: Report
Label Text : (null)
Id of object : f0f47920-f449-4fd0-a74e-804546905437
Any insight into this would be fantastic. Thanks!
The output of the UILabel's text field is null because the label property is not actually linked to anything until the view is loaded. In this case, it wont happen until after you push the view. In order to get around this, you can just have a property on your DetailViewController that holds the string until the view appears.
Then in viewDidLoad or viewWillAppear in DetailViewController, you can set the text on objIdLabel to the property that contains the string
The problem can come from the DetailViewController implementation.
DetailViewController *detailView = [[DetailViewController alloc] init];
only init the Controller
but you declare
#interface DetailViewController : UIViewController
#property (weak, nonatomic) IBOutlet UILabel *objId;
#end
wich means you must use a xib.
So you first have to use
DetailViewController *detailView = [[DetailViewController alloc] initWithNibName:#"DetailViewXIBName" bundle:nil];
then try to affect the value to objIdLabel once the controller is pushed:
- (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath{
DetailViewController *detailView = [[DetailViewController alloc] initWithNibName:#"DetailViewXIBName" bundle:nil];
[self.navigationController pushViewController:detailView animated:YES];
detailView.objIdLabel.text = [[self.objArray objectAtIndex:indexPath.row] objId];
NSLog(#"Object Selection: Report");
NSLog(#"Label Text : %#", detailView.objId.text);
NSLog(#"Id of object : %#", [[self.objArray objectAtIndex:indexPath.row] objId]);
}
You have to affect the text after [super viewDidLoad]; is called.
These are just assumptions as we only have limited information
It may push a blank view controller because you are not strongly holding onto the detailView.
Try adding:
#property (nonatomic, strong) DetailViewController *detailView;
to the main ViewController, then in the didSelectItemAtIndexPath method:
// Implement action for object selection
- (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath{
self.detailView = [[DetailViewController alloc] init];
self.detailView.objIdLabel.text = [[self.objArray objectAtIndex:indexPath.row] objId];
[self.navigationController pushViewController:self.detailView animated:YES];
}
It turns out this comes down to a xib's lifecycle. It is true, as many of you suggested, that the detailView is not actually linked with all of the items associated with it (like the objId UILabel) until it's loaded.
I ended up fixing this by creating a new singleton model object to hold onto the selected object. I was then able to set the selected object on the singleton from my main view controller and call it from the detailView to set my objId on ViewDidLoad.

xCode Detail View is Empty

I am creating an iPad application (iOS6.1) which has a master detail view concept. First view is a table view has list of items that are been loaded from Plist, when each row gets selected the second table view gets loaded with another Plist. theirs is my Detail view which has to display an UIView with a UILabel ans an UIImage. I am using didSelectRowAtIndexPath method . The first two table Views are been displayed properly and loads the row and display corresponding View but the last detail view which is supposed to display the UILabel and an image is empty, can any one help me to solve this problem
My Code for the didSelectRowAtIndexPath method is
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
TaskDetailViewController *newTaskDetailViewController = [[TaskDetailViewController alloc] init];
// pass the row to newDetailViewController
if (weekNumber == 0)
{
newTaskDetailViewController.taskdescription = [weeklist1 objectAtIndex:indexPath.row];
}
if (weekNumber == 1)
{
newTaskDetailViewController.taskdescription = [weeklist2 objectAtIndex:indexPath.row];
}
if (weekNumber == 2)
{
newTaskDetailViewController.taskdescription = [weeklist3 objectAtIndex:indexPath.row];
}
// ...... repeated for 39 times because of the list
newTaskDetailViewController.taskNumber = indexPath.row;
[self.navigationController pushViewController:newTaskDetailViewController animated:YES];
}
DetailView header
#import <UIKit/UIKit.h>
#interface TaskDetailViewController : UIViewController
#property int taskNumber;
#property(strong , nonatomic) NSString *taskdescription;
#property (nonatomic , strong) NSMutableDictionary * tasks;
#property (strong, nonatomic) IBOutlet UIImageView *questionImage;
#property (strong, nonatomic) IBOutlet UILabel *displayText;
#end
Implemetation file has
#implementation TaskDetailViewController
#synthesize taskNumber;
#synthesize taskdescription;
#synthesize tasks;
#synthesize displayText;
#synthesize questionImage;
-(void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view.
self.title = taskdescription;
NSLog(#"%#", taskdescription);
}
Your problem is using alloc init to create an instance of TaskDetailViewController. You've created that controller in the storyboard so you should instantiate it from the storyboard using an identifier that you give it (DetailViewController in my example):
TaskDetailViewController *newTaskDetailViewController = [self.storyboard instantiateViewControllerWithIdentifier:#"DetailViewController"];

how to pass data from tableview to another tableview cell?

I am using static UITableView to show profile of a customer.
It has SelectCountryCell to select country which, when clicked, opens new UITableView with country list.
When I select country from Country TableView, It should display in previous TableView's SelectCountryCell.
How do I do this?
You should bind the static cells to outlets in your UITableViewController and put the profile syncing methods to the - viewWillAppear method.
When the user changes the country in the Country list the profile updates. After that when the user moves back to the UITableViewController instance with static content the profile data will be automatically updated.
You can define a delegate in your CityTableView and then define a method in this delegate.
You should realize this method in your CountryTableView.
Then you may get what you want.
I only offer you a thought. You should find the detail by yourself.
MasterViewController.h
#import "DetailViewController.h"
#interface MasterViewController : UITableViewController <DetailProtocol> // Note this.
#property (strong, nonatomic) DetailViewController *detailViewController;
#property (strong, nonatomic, readwrite) NSString *selectedCountry;
#end
MasterViewController.m
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
if (!self.detailViewController) {
self.detailViewController = [[DetailViewController alloc] initWithNibName:#"DetailViewController" bundle:nil];
}
self.detailViewController.delegate = self; // THIS IS IMPORTANT...
[self.navigationController pushViewController:self.detailViewController animated:YES];
}
// Note this -- It's a delegate method implementation
- (void)setCountry:(NSString *)country
{
self.selectedCountry = country;
}
DetailViewController.h
#protocol DetailProtocol <NSObject>
-(void)setCountry:(NSString *)country;
#end
#interface DetailViewController : UIViewController
#property (strong, nonatomic) IBOutlet UITableView *tableView;
#property (unsafe_unretained) id <DetailProtocol> delegate; // Note this
#end
DetailViewController.m
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
[self.tableView deselectRowAtIndexPath:indexPath animated:YES];
[self.delegate setCountry:[countries objectAtIndex:indexPath.row]]; // Note this
[self.navigationController popViewControllerAnimated:YES];
}

Resources