Passing name of cell to another view via table cell button - ios

Alright, so I want to pass the name contained in a cell of a table in one view controller to an array in another view controller. I want to do this via a button that is also contained in the cell of the first table.
Here is where the table cells are described:
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
// add "add" button
UIButton *addFriendButton = [UIButton buttonWithType:UIButtonTypeContactAdd];
addFriendButton.frame = CGRectMake(250.0f, 5.0f, 75.0f, 30.0f);
[cell addSubview:addFriendButton];
[addFriendButton addTarget:self
action:#selector(addFriend:)
forControlEvents:UIControlEventTouchUpInside];
if(!cell)
{
cell = [[UITableViewCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
cell.textLabel.text = [array objectAtIndex:indexPath.row];
return cell;
}
And here is where the button method would be described:
- (IBAction)addFriend:(id)sender
{
NSLog(#"Add friend.");
}
The name of the first view controller - the one doing the pass - is called ViewController - and the second view controller - the one receiving the passed info - is called MyMealViewController. The array that I want the passed info to be stored in is called myMenuArray.
I think that's basically all the relevant information. If there is any additional information that you need from me - or if you need clarification on the question I'm asking - to make my question answerable, please let me know!

You can use
cell.textLabel.text = [array objectAtIndex:indexPath.row];
[[addFriendButton addTarget:self
action:#selector(addFriend:) toTarget:self withObject:cell.textLabel.text]
forControlEvents:UIControlEventTouchUpInside];
- (void)addFriend:(NSString *)theFriendName
{
NSLog(#"Add friend.");
// Now here you make the instance of the new ViewController and you set the text you are adding.
MyViewController *theVC = [MyViewController alloc] initWithNibName:#"MyViewController" bundle:nil];
[theVC setNewFriend:theFriendName];
[self presentModalViewController:theVC animated:YES];
}

Related

Table view scrolling / dequeueReusableCell issue

I have a table view & a custom cell. the cell contains 3 buttons (check box type) . on button click the respective buttons text i need to change (check / uncheck).
I achieved this, but when i click 1st button on top cell and scroll down the new cell at the bottom also has this check mark, and when i scroll back to top the check mark is moved to next cell.. how to fix this??
code:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *strCellIdentifier = #"RemoteCell";
RemoteCustomCell *cell = (RemoteCustomCell*)[tableView ![dequeueReusableCell][2]WithIdentifier:strCellIdentifier];
if (cell == nil) {
cell = [[RemoteCustomCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:strCellIdentifier];
}
else {
cell = [cell initWithStyle:UITableViewCellStyleDefault reuseIdentifier:strCellIdentifier];
}
[cell.btnCheck1 addTarget:self action:#selector(CheckButton1_Click:) forControlEvents:UIControlEventTouchUpInside];
}
return cell;
}
- (void)CheckButton1_Click:(UIButton*)sender
{
RemoteControllCustomCell *clickedCell = (RemoteControllCustomCell *)[[sender superview] superview];
if(clickedCell.btnCheck1.selected)
{
[clickedCell.btnCheck1 setTitle:#"O" forState:UIControlStateNormal];
clickedCell.btnCheck1.selected = NO;
}
else
{
[clickedCell.btnCheck1 setTitle:#"X" forState:UIControlStateSelected];
clickedCell.btnCheck1.selected = YES;
}
}
screenshot:
In your RemoteCustomCell.m file you should implement
- (void)prepareForReuse
{
[super prepareForReuse];
cell.btnCheck1.selected = NO;
}
This way every cell that is reused will have it's btnCheck1.selected value set to NO, and when you load your cell in cellForRowAtIndexPath it will only set it to YES when the cell comes visible and you set it to that.
But it is key to store all your values in an NSMutableArray. There is no such thing as storing your values in the cells only, they get reused on a basis that can not be foreseen. Add your values to the array and use [myArray objectAtIndex:indexPath.row]; to open those values in a cell.
An example:
Somewhere in viewDidLoad
NSMutableArray *myArray = [[NSMutableArray alloc] initWithObjects:#"1", #"0", #"1", #"1", nil];
In your cellForRowAtIndexPath
BOOL yesOrNo = [[myArray objectAtIndex:indexPath.row] boolValue];
And then set your button.selected to the boolean.
This is a typical issue, where you are relying on the UI to the job of your model. The model, the thing that you should pass to your UITableViewCell, so it can be built, would tell it, if it should be displaying an "X" or an "O". Since you are not doing this, the easiest solution, would be to simply reset the state of the cell everytime it gets dequeued.
I think you need to store the state in a array and check the state in
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
CheckButton1_Click do change the state, but when dequeueReusableCell , it loads from cellForRowAtIndexPath again.
It seems like you have dequeue of cell issue. You may implement cellForRowAtIndexPath method as below.
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"RemoteCell";
RemoteCustomCell *cell = (RemoteCustomCell *) [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell==nil) {
NSArray *arrNib=[[NSBundle mainBundle] loadNibNamed:CellIdentifier owner:self options:nil];
cell= (RemoteCustomCell *)[arrNib objectAtIndex:0];
}
[cell.btnCheck1 addTarget:self action:#selector(CheckButton1_Click:) forControlEvents:UIControlEventTouchUpInside];
return cell;
}

Having problems with the method: prepareForReuse

I have a custom UITableViewCell, and when it's selected, it expands and adds a UILabel to the selected cells UIView that I added in the storyBoard.
When I run the app and select a cell, the label gets added to myView as expected. The problem is, when I scroll down, the label is also shown at another cell.
Apparently the reason its behaving like so, is because I'm reusing the cell and I don't clean them as Emilie stated. I'm trying to call the method of prepareForReuse and 'cleaning' the cell, but I'm having trouble doing that. Here is my code:
- (void)prepareForReuse {
NSArray *viewsToRemove = [self.view subviews];
for (UILablel *v in viewsToRemove) {
[v removeFromSuperview];
}
Doing that, cleans even the selected cells label.
- (void)viewDidLoad {
self.sortedDictionary = [[NSArray alloc] initWithObjects:#"Californa", #"Alabama", #"Chicago", #"Texas", #"Colorado", #"New York", #"Philly", #"Utah", #"Nevadah", #"Oregon", #"Pensilvainia", #"South Dekoda", #"North Dekoda", #"Iowa", #"Misouri", #"New Mexico", #"Arizona", #"etc", nil];
self.rowSelection = -1;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
CategorieCell *customCell = [tableView dequeueReusableCellWithIdentifier:#"cellID" forIndexPath:indexPath];
customCell.title.text = [self.sortedDictionary objectAtIndex:indexPath.row];
return customCell;
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
[tableView deselectRowAtIndexPath:indexPath animated:YES];
CategorieCell *customCell = (CategorieCell *)[tableView cellForRowAtIndexPath:indexPath];
if (self.info) {
[self.info removeFromSuperview];
}
self.info = [[UILabel alloc] init];
[self.info setText:#"Hello"];
[self.info setBackgroundColor:[UIColor brownColor]];
CGRect labelFrame = CGRectMake(0, 0, 50, 100);
[self.info setFrame:labelFrame];
[customCell.infoView addSubview:self.info];
NSLog(#"%ld", (long)indexPath.row);
self.rowSelection = [indexPath row];
[tableView beginUpdates];
[tableView endUpdates];
}
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
if ([indexPath row] == self.rowSelection) {
return 159;
}
return 59;
}
The answer is quite simple : you reuse your cell like you should, but never clean them
Reusing your UITableViewCell means that the cell you clicked on previously will be reused when it will go off-screen.
When clicked, you add a view to your UITableViewCell. When reused, the view is still there because you never remove it.
You have two choices : One, you could set a tag of the self.info view (or check with the indexpath you're keeping in memory), then check when you dequeue the cell if the info view is there, and remove it. The cleaner solution would be to implement the view removal by overriding the prepareForReuse method of your custom UITableViewCell
Precision
The first thing you need to do is set a tag for your self.info view after initializing it:
[self.info setTag:2222];
If you want to keep it as simple as possible, you could check and remove the self.info view directly in your cellForRowAtIndexPath method :
CategorieCell *customCell = [tableView dequeueReusableCellWithIdentifier:#"cellID" forIndexPath:indexPath];
customCell.title.text = [self.sortedDictionary objectAtIndex:indexPath.row];
if [customCell.infoView viewWithTag: 2222] != nil {
[self.info removeFromSuperview]
}
return customCell;
I am not a percent sure this code compiles, I cannot test it on my side for now. Hope it works !

Custom UITableViewCell weird behavior with fast scroll

I have a grouped tableView with 5 sections. The tableView uses a custom UITableViewCell with 2 label and 4 buttons in it. When i select 1 or more buttons at the beginning of the table and then scroll to the end of it, i find those buttons selected in the last cell, sometimes in the second-last. It seems to me that there is some issues with the dequeueReusableCellWithIdentifier but i cannot figure it out.
For clarity i have this code in my viewDidLoad:
// table cell
UINib *nib = [UINib nibWithNibName:#"SMRateMeetingTableViewCell" bundle:nil];
[self.tableView registerNib:nib forCellReuseIdentifier:#"SMRateMeetingTableViewCell"];
and this in my cellForRowAtIndexPath:
SMRateMeetingTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"SMRateMeetingTableViewCell" forIndexPath:indexPath];
// Configure the cell...
if (cell == nil) {
cell = [[SMRateMeetingTableViewCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:#"SMRateMeetingTableViewCell"];
}
Pretty basic stuff.
I added some screens for better understanding.
EDIT: adding buttons code.
For an easier analysis let's assume i only have 1 button in the custom cell
This is the table view code:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
SMRateMeetingTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"SMRateMeetingTableViewCell" forIndexPath:indexPath];
// Configure the cell...
if (cell == nil) {
cell = [[SMRateMeetingTableViewCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:#"SMRateMeetingTableViewCell"];
}
//the tag will allow me to understand in which section is the button
cell.firstYesButton.tag = indexPath.section;
[cell.firstYesButton addTarget:self action:#selector(firstYesButtonAction:) forControlEvents:UIControlEventTouchUpInside];
return cell;
}
And the relative method associated to the button:
-(IBAction)firstYesButtonAction:(id)sender
{
UIButton *senderButton = (UIButton *)sender;
[self.votesArray replaceObjectAtIndex:(senderButton.tag*2) withObject:[NSNumber numberWithInt:1]];
//NSLog(#"%#", self.votesArray );
}
An this is the code in the implementation file of the custom cell:
#implementation SMRateMeetingTableViewCell
- (void)awakeFromNib {
// Initialization code
[self.firstYesButton setImage:[UIImage imageNamed:#"yesRateDisable.png"] forState:UIControlStateNormal];
}
- (IBAction)firstYesAction:(id)sender {
[self.firstYesButton setImage:[UIImage imageNamed:#"yesRateEnable.png"] forState:UIControlStateNormal];
}
This is because the table view is recycling your cell. This is what the dequeueReusableCellWithIdentifier: method is doing. Because it is recycling views instead of a new one always being created, you will have to set certain properties, such as the selected state of your buttons, otherwise they will retain the properties that they had when they were enqueued.
As UITableViewCell's get recycled which is quite unpredictable.
So one approach is to maintain the state with key value pairs
that this NSDictionary and set images as per state changed in NSDictionary like
#{
"0":"EnableImage",
"1":"DisableImage",
"2":"DisableImage",
"3":"EnableImage",
}
so set image as per the above dictionary in cellForRowAtIndexPath.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
.... ....
You need set image as per state maintained in above dictionary
return cell;
}
And Remove below code
(void)awakeFromNib {
// Initialization code
[self.firstYesButton setImage:[UIImage imageNamed:#"yesRateDisable.png"] forState:UIControlStateNormal];
}
- (IBAction)firstYesAction:(id)sender {
[self.firstYesButton setImage:[UIImage imageNamed:#"yesRateEnable.png"] forState:UIControlStateNormal];
}

Tableview button click need pickerview in ios

Creating the UIpickerview in tableview button click. When click the each button first time the picker want to show . if i click the same button in another time picker want to hide and get the picker value. here i put my code only the last cell index done the process the first cell index is not working? how can i fix this issues help me!!! here screen!.
create the picker in global like
UIPickerView *myPickerView;` and acess in tableview
-(NSInteger)numberOfSectionsInTableView:(UITableView *)tableView{
return 1;
}
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{
return [_arr_tags count]; /// in tag array number of button count
}
-(UITableViewCell*)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil)
{
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:nil];
cell.selectionStyle = UITableViewCellSelectionStyleNone;
/// create a button
UIImage *ButtonImagecmt = [UIImage imageNamed:#"orangeButton#2x.png"];
UIButton *myButtoncmt = [UIButton buttonWithType:UIButtonTypeRoundedRect];
myButtoncmt.frame = CGRectMake(10,50,90,35);
[myButtoncmt setBackgroundImage:ButtonImagecmt forState:UIControlStateNormal];
[myButtoncmt addTarget:self action:#selector(picker_select:)forControlEvents:UIControlEventTouchDown];
[cell addSubview:myButtoncmt];
flg=1; /// first time picker want to hide so flag set 1.
myPickerView = [[UIPickerView alloc] initWithFrame:CGRectMake(120, 0, 160, 180)];
myPickerView.delegate = self;
myPickerView.showsSelectionIndicator = YES;
myPickerView.hidden=true;
[cell addSubview:myPickerView];
}
return cell;
}
- (IBAction)picker_select:(id)search
{
if (flg==1)
{
/// first time button clickt picker want to display
myPickerView.hidden=false;
flg=0;
}
else
{
/// secound time button click picker want to hide
myPickerView.hidden=true;
flg=1;
}
}
This code only working in last cell. want to work in all the cell in table view
First let me explain your error after that I will suggest you other way.
You are declaring UIPickerView *myPickerView; in out side of following method
-(UITableViewCell*)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
But you are initializing myPickerView inside of following method
-(UITableViewCell*)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
and again you are trying to access myPickerView outside of the following method
-(UITableViewCell*)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
simply the object myPickerView represents last cell pickerview. so what ever button you tapped in table view, myPickerView always represents last cell pickerview. As per reusability concept, you can't see this picker until you are loading last cell on screen.
so what I am suggesting you to work with your code
set index row as tag to your button like bellow in cellForRowAtIndexPath method
myButtoncmt.tag = indexpath.row;
now in the same way set tag to your pickerview also(I am not recommended this but I am trying to resolve issue with your code ) like bellow
myPickerView.tag = [_arr_tags count]+indexpath.row;
Now in - (IBAction)picker_select:(id)search access that using following code
UIButton *tempBtn =(UIButton *) search;
UITableViewCell *cell= [_tableView cellForRowAtIndexPath:[NSIndexPath indexPathForRow:tempBtn.tag inSection:0]]
UIPickerView *pickerView = [cell viewWithTag:[_arr_tags count]+tempBtn.tag];
pickerView.hidden = !pickerView.isHidden;
Now you can see all pickers. try and let me know your result

Add xib as a view to cover a custom UITableViewCell in editing mode

I'm trying to to something like apple's alarm clock, when tap the edit button, a custom view cover the custom UITableViewCell.
The code above:
// CGRect frame = [tableView rectForRowAtIndexPath:indexPath];
// CGPoint yOffset = self.tableViewBlock.contentOffset;
// CGRect newFrame = CGRectMake(frame.origin.x, (frame.origin.y - yOffset.y + 45), frame.size.width, frame.size.height);
CallBlock_Date_EditMode *viewController = [[CallBlock_Date_EditMode alloc] initWithNibName:#"CallBlock_Date_EditMode" bundle:nil];
// self.view.frame = newFrame;
// [self.view addSubview:viewController.view];
// [self addChildViewController:viewController];
UITableViewCell *cell = (UITableViewCell*)[self.tableViewBlock cellForRowAtIndexPath:indexPath];
[cell.contentView addSubview:viewController.view];
Cover the specific cell when I put in under:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
Just to make sure the size is ok (although when I tap a button in that xib the app crash without even a single error).
But I want to do like apple's alarm clock (actually, mimic it), tap my edit button and my custom UITableViewCell will get cover with this xib as a view.
Maybe there is a better approach to do it?
EDIT:
My updated code is:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
CallBlock_TableCell *cell = (CallBlock_TableCell*)[tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
if (cell == nil)
{
cell = [[CallBlock_TableCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
// Configure the cell...
[self configureCell:cell atIndexPath:indexPath];
return cell;
}
- (void)configureCell:(CallBlock_TableCell *)cell atIndexPath:(NSIndexPath *)indexPath
{
cell.accessoryType = self.isEditing ? UITableViewCellAccessoryDisclosureIndicator : UITableViewCellAccessoryNone;
CallBlock_ByDate *callBlock = (CallBlock_ByDate*)[fetchedObjects objectAtIndex:indexPath.row];
cell.labelTime.text = callBlock.startDate;
cell.labelRepeat.text = callBlock.repeat;
cell.labelTextLabel.text = callBlock.label;
cell.switchCallBlock.on = YES;
cell.switchCallBlock.tag = (NSInteger)indexPath.row +1;
[cell.switchCallBlock addTarget:self action:#selector(handleSwitch:) forControlEvents:UIControlEventValueChanged];
cell.switchCallBlock.hidden = self.isEditing ? YES : NO;
if (self.isEditing)
{
cell.switchCallBlock.hidden = YES;
UIButton *btnArrow = [[UIButton alloc] init];
btnArrow.frame = CGRectMake(282.0, 31.0, 18.0, 21.0);
[btnArrow setBackgroundImage:[UIImage imageNamed:#"arrow_FWR_off"] forState:UIControlStateNormal];
[btnArrow setBackgroundImage:[UIImage imageNamed:#"arrow_FWR_on"] forState:UIControlStateHighlighted];
btnArrow = [UIButton buttonWithType:UIButtonTypeCustom];
[btnArrow addTarget:self action:#selector(handleTapToEdit:) forControlEvents:UIControlEventTouchUpInside];
btnArrow.tag = indexPath.row + 1;
[cell.contentView addSubview:btnArrow];
[cell.contentView bringSubviewToFront:btnArrow];
}
}
But I cannot get the btnArrow appear on the UTableView.
The reason you are getting a crash is because nothing is retaining your CallBlock_Date_EditMode view controller. You add its view to your cell as a subview, but nothing maintains a reference to the view controller, so it is deallocated and then, when pressing a button that is supposed to pass a message to your view controller, it is sent to a deallocated object and you get a crash.
There are two possible solutions to this. First, you could store that view controller in one of your properties to maintain a reference to it so that it does not deallocated. This is, for the most part, probably not what you want.
Instead, what I would suggest doing is do not make your CallBlock_Date_EditMode a UIViewController, but instead make it a UIView. You may be wondering "But how can I use a xib without a UIViewController?". I would do something like the following:
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self)
{
UIView *view = [[[NSBundle mainBundle] loadNibNamed:#"CallBlock_Date_EditMode" owner:self options:nil] objectAtIndex:0];
self.myEditButton = (UIButton *)[view viewWithTag:2];
[self addSubview:view];
}
return self;
}
This would be code inside your custom UIView that would load in a xib file and add it as a subview. In order to get access to your subviews, you have to use tags inside interface builder, so you do lose the convenience of drawing/connecting IBOutlets... But in the end, it is much better than allocating/storing a bunch of unnecessary UIViewControllers.
If I understand you right and you want to mimic the functionality of the alarm clock that comes pre-installed from Apple, your solution is much simpler than creating a custom view. It looks like all they do is set the On-Off switches to hidden and add a disclosure indicator to the cell. This is what I would do...
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
bool hide = (tableView.editingStyle == UITableViewCellEditingStyleDelete); // set to true or false depending on if the table is in editing mode
for (UIView *sv in [cell subviews] ) {
if([sv isKindOfClass:[UISwitch class]]) { // find the on-off switch
[sv setHidden:hide]; // hide the switch depending on the t/f value of hide
break;
}
}
if(hide) { // adds the arrow like in apple's alarm clock table if the cell is in edit mode
[cell setAccessoryType:UITableViewCellAccessoryDisclosureIndicator];
}
else {
[cell setAccessoryType:UITableViewCellAccessoryNone];
}
return cell;
}

Resources