FirstPage.h
#import <UIKit/UIKit.h>
#import "StudentPage.h"
#interface FirstPage : UIViewController <UITableViewDelegate,UITableViewDataSource,StudentInfoDelegates>
#property (strong, nonatomic) IBOutlet UITableView *tableView;
- (IBAction)addButtonAction:(id)sender;
#end
FirstPage.m
#import "FirstPage.h"
#interface FirstPage ()
#end
#implementation FirstPage
{
NSMutableArray *firstPageArray;
}
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib
//[self performSegueWithIdentifier:#"StudentInfo" sender:sender];
/*StudentPage *student=[[StudentPage alloc]init];
student.delegates=self;*/
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
//the next following didn't created..
//the RowAtIndexPath are not been executed..
-(UITableViewCell*)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
NSString *concateValue=#"";
NSMutableDictionary *studentSecondDictionary=[[NSMutableDictionary alloc]init];
static NSString *CellIdentifier=#"Cell";
UITableViewCell *cell=[tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if(cell==nil){
cell=[[UITableViewCell alloc]initWithFrame:CGRectZero];
[cell setBackgroundColor:[UIColor redColor]];
[cell setSelectionStyle:UITableViewCellSelectionStyleNone];
[cell setIndentationWidth:0.0];
studentSecondDictionary=[firstPageArray objectAtIndex:indexPath.row];
NSString *name1=[studentSecondDictionary valueForKey:#"NAME"];
NSString *regno1=[studentSecondDictionary valueForKey:#"REGNO"];
NSString *marks1=[studentSecondDictionary valueForKey:#"MARKS"];
NSString *rank1=[studentSecondDictionary valueForKey:#"RANK"];
concateValue=[[[[[[name1 stringByAppendingString:#" "]stringByAppendingString:regno1]stringByAppendingString:#" "]stringByAppendingString:marks1]stringByAppendingString:#" "]stringByAppendingString:rank1];
cell.textLabel.text=concateValue;
}
return cell;
}
-(NSInteger)numberOfSectionsInTableView:(UITableView *)tableView{
return 1;
}
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{
return firstPageArray.count;
}
-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath{
return 50;
}
- (IBAction)addButtonAction:(id)sender {
StudentPage *stdView=[self.storyboard instantiateViewControllerWithIdentifier:#"MyIdentifier"];
stdView.delegates=self;
[self.navigationController pushViewController:stdView animated:YES];
//[self.view addSubview:stdView.view];
}
-(void)didFinishSave:(NSMutableArray *)in_studentList{
firstPageArray=[[NSMutableArray alloc]init];
firstPageArray=in_studentList;
[self.tableView reloadData];
}
#end
StudentPage.h
#import <UIKit/UIKit.h>
#protocol StudentInfoDelegates
-(void)didFinishSave:(NSMutableArray*)in_studentList;
#end
#interface StudentPage : UIViewController<UITextFieldDelegate>
#property(assign,nonatomic)id<StudentInfoDelegates> delegates;
#property (strong, nonatomic) IBOutlet UITextField *name;
#property (strong, nonatomic) IBOutlet UITextField *regno;
#property (strong, nonatomic) IBOutlet UITextField *marks;
#property (strong, nonatomic) IBOutlet UITextField *rank;
- (IBAction)save:(UIButton *)sender;
#end
StudentPage.m
#import "StudentPage.h"
#import "FirstPage.h"
#implementation StudentPage
{
NSMutableArray *studentArray;
NSMutableDictionary *StudentDictionary;
}
#synthesize name,regno,marks,rank;
#synthesize delegates;
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{
[self.view endEditing:YES];
[super touchesBegan:touches withEvent:event];
}
- (IBAction)save:(UIButton *)sender {
studentArray=[[NSMutableArray alloc]init];
StudentDictionary=[[NSMutableDictionary alloc]init];
[StudentDictionary setValue:name.text forKey:#"NAME"];
[StudentDictionary setValue:regno.text forKey:#"REGNO"];
[StudentDictionary setValue:marks.text forKey:#"MARKS"];
[StudentDictionary setValue:rank.text forKey:#"RANK"];
[studentArray addObject:StudentDictionary];
[delegates didFinishSave:studentArray];
NSLog(#"%#",studentArray);
FirstPage *firstView=[self.storyboard instantiateViewControllerWithIdentifier:#"MyIdentifier1"];
[self.navigationController pushViewController:firstView animated:YES];
}
#end
As #BiWoj said in the comments, you are checking for
if (cell==nil)...
and rely on that check to go through the first time so you can fill out your data. This is wrong, you instead dequeue the cell and then when it's not nil you can start putting your data in its views. The only reason that cell will be nil is when you dequeue, using a non-existent identifier i.e. it should never happen.
First just check your delegate method is getting called or not when you click on save button.
I think you forgot to set delegate to self before
[delegates didFinishSave:studentArray];
It should be
self.delegate = delegates
[delegates didFinishSave:studentArray];
If this does not work please check that, you are pushing student page from first page like this
- (IBAction)addButtonAction:(id)sender {
StudentPage *stdView=[self.storyboard instantiateViewControllerWithIdentifier:#"MyIdentifier"];
stdView.delegates=self;
[self.navigationController pushViewController:stdView animated:YES];}
And one again on your save action method of student page you are pushing first page like this.
FirstPage *firstView=[self.storyboard instantiateViewControllerWithIdentifier:#"MyIdentifier1"];
[self.navigationController pushViewController:firstView animated:YES];
Well i guess instead of that you have to just use
[self.navigationController popToRootViewControllerAnimated:YES];
There is no need to push again the same controller you just have to pop to base controller.
Related
I'm having two view controller A and B. when click button on view controllerA it will navigate to view controllerB and their is a tableview with textlabel,when i click on tableviewcell i want to navigate back into viewcontrollerA and want to pass that textlabel value back to viewcontrollerA
if you are using push seque is the worst way, reason you increase the memory in your stack trace.
you can do this in multiple ways, search once in google you get multiple answer related to this
UnWind Segue
Protocols & delegates
local database method
using Singleton class.
Using bean object method.
using Plist
finally go for NSUserDefault
I created a sample using Protocols and Delegates, as follows:
ViewController.m
#import "ViewController.h"
#import "ColorsTableViewController.h"
#interface ViewController () <ColorsDelegate>
#property (weak, nonatomic) IBOutlet UILabel *textDataLabel;
- (IBAction)goButtonTapped:(id)sender;
#end
#implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (void)sendColor:(NSString *)colorName{
self.textDataLabel.text = colorName;
}
- (IBAction)goButtonTapped:(id)sender {
ColorsTableViewController *colorsTableViewController=(ColorsTableViewController *)[self.storyboard instantiateViewControllerWithIdentifier:#"colorTableIdentifier"];
colorsTableViewController.delegate = self;
[self.navigationController pushViewController:colorsTableViewController animated:YES];
}
#end
ColorsTableViewController.h
#import <UIKit/UIKit.h>
#protocol ColorsDelegate <NSObject>
#optional
- (void)sendColor:(NSString *)colorName;
#end
#interface ColorsTableViewController : UIViewController
#property (nonatomic, assign) id<ColorsDelegate> delegate;
#end
ColorsTableViewController.m
#import "ColorsTableViewController.h"
#interface ColorsTableViewController () <UITableViewDelegate, UITableViewDataSource>
#property (weak, nonatomic) IBOutlet UITableView *colorsTableView;
#property (strong, nonatomic) NSArray *colorsArray;
#end
#implementation ColorsTableViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
self.colorsArray = #[#"Red",#"Green",#"Blue",#"Brown",#"Yellow"];
[self.colorsTableView registerClass:[UITableViewCell class] forCellReuseIdentifier:#"colorCell"];
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{
return self.colorsArray.count;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
UITableViewCell *myCell = [self.colorsTableView dequeueReusableCellWithIdentifier:#"colorCell" forIndexPath:indexPath];
UILabel *myTextLabel = [myCell.contentView viewWithTag:100];
if(!myTextLabel)
{
myTextLabel = [[UILabel alloc]initWithFrame:CGRectMake(10, 5, CGRectGetWidth(myCell.frame), CGRectGetHeight(myCell.frame))];
myTextLabel.tag = 100;
}
myTextLabel.text = self.colorsArray[indexPath.row];
[myCell.contentView addSubview:myTextLabel];
return myCell;
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{
UITableViewCell *myCell = (UITableViewCell *)[self.colorsTableView cellForRowAtIndexPath:indexPath];
UILabel *myTextLabel = [myCell.contentView viewWithTag:100];
if(myTextLabel)
{
[_delegate sendColor:myTextLabel.text];
}
}
Screenshot:
Here is my GitHub Link, please download and check:
https://github.com/k-sathireddy/sendDataBack
I'm using the UITableview like below image. If i typing Unit price and Qty i need to calculate. But now i dont know how to get indexpath for two text box in UITableView . In UITableView if button clicking goes to didSelectRowAtIndexPath method. Same method not calling when I typing in qty and unitprice textbox.
InvoiceMainViewController.h
#import <UIKit/UIKit.h>
#import <QuartzCore/QuartzCore.h>
#class InvoiceGridViewController;
#protocol InvoiceTableCellProtocoll <NSObject>
-(void) didPressButton:(InvoiceGridViewController *)theCell;
#end
#interface InvoiceGridViewController : UITableViewCell {
id<InvoiceTableCellProtocoll> delegationListener; }
#property (nonatomic,assign) id<InvoiceTableCellProtocoll> delegationListener;
#property (nonatomic,retain) IBOutlet UITextField *invoiceItem;
#property (nonatomic,retain) IBOutlet UITextField *invoiceUnitPrice;
#property (nonatomic,retain) IBOutlet UITextField *invoiceQty;
#property (nonatomic,retain) IBOutlet UITextField *invoiceTaxRate;
#property (nonatomic,retain) IBOutlet UILabel *invoiceItemId;
#property (nonatomic,retain) IBOutlet UILabel *invoiceCurrencyId;
#property (nonatomic,retain) IBOutlet UILabel *invoiceTaxRateId;
#property (nonatomic,retain) IBOutlet UILabel *totalItemTax; #property
#property (nonatomic,retain) IBOutlet UILabel *converstionMessage;
-(IBAction)deleteSel:(id)sender;
-(void)delFileSel;
#end
InvoiceMainViewController.m
#import <UIKit/UIKit.h>
#import "SBPickerSelector.h"
#import <Foundation/Foundation.h>
#import "AFHTTPRequestOperationManager.h"
#import "AFURLResponseSerialization.h"
#import "AFURLRequestSerialization.h"
#import "InvoiceGridViewController.h"
#interface InvoiceMainViewController : UIViewController<UITableViewDataSource, UITableViewDelegate,NSXMLParserDelegate,UITextFieldDelegate,InvoiceTableCellProtocoll>{
you can do this in various methods
Type -1
// get the current visible rows
NSArray *paths = [yourtableName indexPathsForVisibleRows];
NSIndexPath *indexpath = (NSIndexPath*)[paths objectAtIndex:0];
Type-2
you can get which cell you touched
CGPoint touchPoint = [sender convertPoint:CGPointZero toView: yourtableName];
NSIndexPath *clickedButtonIndexPath = [mainTable indexPathForRowAtPoint: yourtableName];
Type-3
add `TapGestuure ` for get the current cell.
Type-4
- (void) textFieldDidEndEditing:(UITextField *)textField {
CGRect location = [self convertRect:textField.frame toView:self.tableView];
NSIndexPath *indexPath = [[self.tableView indexPathsForRowsInRect:location] objectAtIndex:0];
// Save the contents of the text field into your array:
[yourArray replaceObjectAtIndex:indexPath.row withObject:textField.text];
}
example
here if you need additional information see this link
Try this one
#import "ViewController.h"
#interface ViewController ()
#end
#implementation ViewController
- (void)viewDidLoad
{
[super viewDidLoad];
firstTxt.delegate = self;
secondTxt.delegate = self;
// Do any additional setup after loading the view, typically from a nib.
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (BOOL)textFieldShouldBeginEditing:(UITextField *)textField{
NSLog(#"textFieldShouldBeginEditing");
textField.backgroundColor = [UIColor colorWithRed:220.0f/255.0f green:220.0f/255.0f blue:220.0f/255.0f alpha:1.0f];
return YES;
}
- (void)textFieldDidBeginEditing:(UITextField *)textField{
NSLog(#"textFieldDidBeginEditing");
}
- (BOOL)textFieldShouldEndEditing:(UITextField *)textField{
NSLog(#"textFieldShouldEndEditing");
textField.backgroundColor = [UIColor whiteColor];
return YES;
}
- (void)textFieldDidEndEditing:(UITextField *)textField{
NSLog(#"textFieldDidEndEditing");
[tableView reloadData];
}
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{
NSLog(#"touchesBegan:withEvent:");
[self.view endEditing:YES];
[super touchesBegan:touches withEvent:event];
}
#pragma mark -
#pragma mark - UITableView Delegates
- (UITableViewCell *)tableView:(UITableView *)tableView1 cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = [tableView1 dequeueReusableCellWithIdentifier:#"FirstTableViewCell"];
if (cell == nil)
{
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:#"FirstTableViewCell"];
// cell = [[UITableViewCell alloc]initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier];
}
if (![firstTxt.text isEqual: #""] && ![secondTxt.text isEqual: #""])
{
NSString *fir = firstTxt.text;
NSString * sec = secondTxt.text;
cell.textLabel.text= [NSString stringWithFormat:#"%d",[fir intValue]+[sec intValue]];
}
else
{
cell.textLabel.text=#"";
}
//etc.
return cell;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return 4;
}
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
// NSLog(#"testing1");
}
- (void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath
{
cell.layer.backgroundColor = [UIColor clearColor].CGColor;
cell.backgroundColor = [UIColor clearColor];
}
#end
.h
//
// ViewController.h
// TestingText
#import <UIKit/UIKit.h>
#interface ViewController : UIViewController<UITableViewDelegate,UITableViewDataSource,UITextFieldDelegate>
{
IBOutlet UITableView *tableView;
IBOutlet UITextField *secondTxt;
IBOutlet UITextField *firstTxt;
}
#end
In textfield delegate method you can get the indexpath of row or you can directly get the textfields text
-(void)textFieldDidEndEditing:(UITextField *)textField
{
CGPoint hitPoint = [txtfield convertPoint:CGPointZero toView:tbl];
hitIndex = [tbl indexPathForRowAtPoint:hitPoint];
int localCount = [txtfield.text intValue];
}
Subclass your UITableViewCells. Create a protocol for each cell, with methods like cellName:(UITableViewCell*)cellName didSelectItem:(Item*) item. You can find more info here.
In the UITableViewCell set your UITextView delegate to self, and implement the protocol. textFieldShouldReturn: method, will indicate when the user is typing, so inside you will call [self.delegate cellName:self didEditText:textField.text].
In your MainViewController tableView: cellForRowAtIndexPath: set the UITabelViewCell's delegates, and implement the protocols.
So you will know in MainViewController when a user has typed in any of your textfields, independently from the table row number.
I have two view controllers, HomeViewController (hereafter HVC) and AddActivityViewController (hereafter AAVC). In AAVC, I've declared a delegate protocol:
#protocol AddActivityViewControllerDelegate;
and defined it thusly:
#protocol AddActivityViewControllerDelegate
-(void) addActivityViewControllerDidSave;
-(void) addActivityViewControllerDidCancel:(ListActivity *) activityToDelete;
#end
Next, I implemented the two methods in HVC (the delegate) like this:
-(void) addActivityViewControllerDidSave
{
[self.moc MR_saveToPersistentStoreAndWait];
[self.navigationController dismissViewControllerAnimated:YES completion:nil];
}
-(void) addActivityViewControllerDidCancel:(ListActivity *) activityToDelete
{
[activityToDelete MR_deleteEntity];
[self.navigationController dismissViewControllerAnimated:YES completion:nil];
}
I get this error "Use of undeclared identifier 'addActivityViewControllerDidSave' even though it's clearly declared in the protocol.
I should mention that before this, I was dealing with what was apparently an "import loop," which caused an "undeclared protocol" error. That error seems to have been fixed.
Here are the #import statements from the HomeViewController.h file:
#import <UIKit/UIKit.h>
#import "ListActivity.h"
#import "AddActivityViewController.h"
#import "TimedActivity.h"
#interface HomeViewController : UIViewController <AddActivityViewControllerDelegate>
#property (strong, nonatomic) IBOutlet UITableView *myTableView;
#property NSManagedObjectContext * moc;
- (IBAction)dumpMemory:(UIButton *)sender;
#end
And from the AddActivityViewController.h file:
#import <UIKit/UIKit.h>
#import "ListActivity.h"
#protocol AddActivityViewControllerDelegate;
#interface AddActivityViewController : UIViewController
#property (weak, nonatomic) IBOutlet UITextField *activityField;
#property (weak, nonatomic) IBOutlet UITextField *categoryField;
#property (strong, nonatomic) ListActivity *thisActivity;
#property (nonatomic, weak) id <AddActivityViewControllerDelegate> delegate;
- (IBAction)saveButton:(UIBarButtonItem *)sender;
- (IBAction)cancelButton:(UIBarButtonItem *)sender;
#end
#protocol AddActivityViewControllerDelegate
-(void) addActivityViewControllerDidSave;
-(void) addActivityViewControllerDidCancel:(ListActivity *) activityToDelete;
#end
I can post the full content of all four class files if that is helpful.
Many thanks for helping!
Edit: Here's the full code from HomeViewController.m:
//
// HomeViewController.m
// MRExample
//
// Created by Tim Jones on 1/15/14.
// Copyright (c) 2014 TDJ. All rights reserved.
//
#import "HomeViewController.h"
#import "ListActivity.h"
#interface HomeViewController ()
{
NSFetchedResultsController *frc;
}
#end
#implementation HomeViewController
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
self.automaticallyAdjustsScrollViewInsets = NO;
[self refreshData];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(notificationNewActivityAdded:) name:#"newActivityAdded" object:nil];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
-(void) notificationNewActivityAdded:(NSNotification*)notification
{
[self refreshData];
}
#pragma mark Table View data source
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return [[frc sections] count];
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
id<NSFetchedResultsSectionInfo> sectionInfo = [[frc sections] objectAtIndex:section];
return [sectionInfo numberOfObjects];
}
// Customize the appearance of table view cells.
- (void)configureCell:(UITableViewCell *)cell atIndexPath:(NSIndexPath *)indexPath {
// Configure the cell to show the activity's name
ListActivity *thisActivity = [frc objectAtIndexPath:indexPath];
cell.textLabel.text = thisActivity.activityName;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
[self configureCell:cell atIndexPath:indexPath];
cell.textLabel.textColor = [UIColor redColor];
NSAttributedString *attString;
attString = cell.textLabel.attributedText;
return cell;
}
// Section Label
- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section
{
NSString *sectionLabel = [[[frc sections] objectAtIndex:section]name];
return [sectionLabel uppercaseString];
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
NSManagedObjectContext *localContext = [NSManagedObjectContext MR_contextForCurrentThread];
ListActivity *thisActivity = [frc objectAtIndexPath:indexPath];
TimedActivity *currentActivity = [TimedActivity MR_createInContext:localContext];
currentActivity.timedActivityName = thisActivity.activityName;
currentActivity.category = thisActivity.activityCategory;
currentActivity.timedActivityTapped = [NSDate date];
[localContext MR_saveToPersistentStoreAndWait];
}
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath
{
if (editingStyle == UITableViewCellEditingStyleDelete)
{
NSManagedObjectContext *localContext = [NSManagedObjectContext MR_contextForCurrentThread];
ListActivity *activityToTrash = [frc objectAtIndexPath:indexPath];
// Delete the row from the data source
[activityToTrash MR_deleteEntity];
[localContext MR_saveToPersistentStoreAndWait];
[self refreshData];
}
}
-(void) refreshData
{
//This was the turning point for proper MR grouping. The two Properties (activityCategory and activityName) are used as Sort descriptors in the underlying core data methods
frc = [ListActivity MR_fetchAllSortedBy:#"activityCategory,activityName" ascending:YES withPredicate:nil groupBy:#"activityCategory" delegate:nil];
[self.myTableView reloadData];
}
- (IBAction)dumpMemory:(UIButton *)sender
{
NSManagedObjectContext *localContext = [NSManagedObjectContext MR_contextForCurrentThread];
[ListActivity MR_truncateAllInContext:localContext];
[localContext MR_saveToPersistentStoreAndWait];
[self refreshData];
}
- (void) prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
NSManagedObjectContext *localContext = [[NSManagedObjectContext alloc] init];
if ([[segue identifier] isEqualToString:#"addActivity"])
{
AddActivityViewController *aavc = (AddActivityViewController *) [segue destinationViewController];
aavc.delegate = self;
ListActivity *newActivity = [ListActivity MR_createInContext:localContext];
aavc.thisActivity = newActivity;
}
-(void) addActivityViewControllerDidSave
{
[self.moc MR_saveToPersistentStoreAndWait];
[self.navigationController dismissViewControllerAnimated:YES completion:nil];
}
-(void) addActivityViewControllerDidCancel:(ListActivity *) activityToDelete
{
[activityToDelete MR_deleteEntity];
[self.navigationController dismissViewControllerAnimated:YES completion:nil];
}
}
#end
Okay, just as I thought. The problem is that you're missing a bracket "}" at the end of the - (void) prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender method. Also you have an extra bracket at the end of the class (right above the #end keyword). That's probably the missing bracket. Fix that and your problem will go away.
Hope this helps!
I don't know if it's the problem, but move the declaration of your delegate (with the #class directive) to the top of AddActivityViewController, like this:
#import <UIKit/UIKit.h>
#import "ListActivity.h"
#class AddActivityViewController;
#protocol AddActivityViewControllerDelegate
- (void)addActivityViewControllerDidSave;
- (void)addActivityViewControllerDidCancel:(ListActivity *) activityToDelete;
#end
#interface AddActivityViewController : UIViewController
#property (nonatomic, weak) id <AddActivityViewControllerDelegate> delegate;
#property (nonatomic, weak) IBOutlet UITextField *activityField;
#property (nonatomic, weak) IBOutlet UITextField *categoryField;
#property (nonatomic, strong) ListActivity *thisActivity;
- (IBAction)saveButton:(UIBarButtonItem *)sender;
- (IBAction)cancelButton:(UIBarButtonItem *)sender;
#end
I have loaded a table view with NSArray data. Now, I want to play a video in a detail view. The video played depends on what cell the user clicks.
How do I test the cell clicked and load a video from the array based on that?
I am using Xcode 5 for iOS 7.
Here is my ViewController.m
#import "ViewController.h"
#import "VideoDetailViewController.h"
#interface ViewController ()
{
NSMutableArray * titlearray;
NSMutableArray * arrayVidSrc;
}
#end
#implementation ViewController
#synthesize mytableview;
- (void)viewDidLoad
{
[super viewDidLoad];
//sets delegate methods of table view
self.mytableview.delegate=self;
self.mytableview.dataSource=self;
//assigns values to objects in array's
titlearray = [[NSMutableArray alloc]initWithObjects:#"intro", #"skating",nil];
arrayVidSrc = [[NSMutableArray alloc]initWithObjects:#"Step1-Intro.mp4", #"Step2-Skating.mp4", nil];
}
// returns one section in the table
-(NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return 1;
}
//counts the items in the title array
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return [titlearray count];
}
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier =#"vidCell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath: indexPath];
cell.textLabel.text = [titlearray objectAtIndex:indexPath.row];
return cell;
}
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([segue.identifier isEqualToString:#"showDetailsSeg"]) {
NSIndexPath *indexpath =nil;
NSString *titlestring =nil;
indexpath = [mytableview indexPathForSelectedRow];
titlestring = [titlearray objectAtIndex:indexpath.row];
NSURL * movieURL = [arrayVidSrc objectAtIndex:indexpath.row];
MPMoviePlayerController *player = [[MPMoviePlayerController alloc] initWithContentURL: movieURL];
[[player view] setFrame: [self.view bounds]];
[self.view addSubview: [player view]];
[player play];
[[segue destinationViewController] setTitlecontents:titlestring];
}
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
#end
And here is my ViewController.h
#import <UIKit/UIKit.h>
#import <MediaPlayer/MediaPlayer.h>
//allows us to use the delegate methods of table view
#interface ViewController : UIViewController <UITableViewDataSource, UITableViewDelegate>
#property (weak, nonatomic) IBOutlet UITableView *mytableview;
#end
I have a custom view controller class VideoDetailViewController.m:
#import "VideoDetailViewController.h"
#interface VideoDetailViewController ()
#end
#implementation VideoDetailViewController
#synthesize arrayVidSrc = _arrayVidSrc;
#synthesize titlelabel;
#synthesize navBar;
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
self.titlelabel.text = self.titlecontents;
self.navBar.title = self.titlecontents;
//video load from array
// NSURL * movieURL = [_arrayVidSrc objectAtIndex:NSIndexPath.row];
//Play the movie now
/*MPMoviePlayerViewController *playercontroller = [[MPMoviePlayerViewController alloc] initWithContentURL:movieURL];
[self presentMoviePlayerViewControllerAnimated:playercontroller];
playercontroller.moviePlayer.movieSourceType = MPMovieSourceTypeFile;
[playercontroller.moviePlayer play];
playercontroller = nil;*/
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
#end
and the .h file that goes with it:
#import <UIKit/UIKit.h>
#import <MediaPlayer/MediaPlayer.h>
#interface VideoDetailViewController : UIViewController
#property (weak, nonatomic) IBOutlet UINavigationItem *navBar;
#property (weak, nonatomic) IBOutlet UILabel *selectedRow;
#property (strong, nonatomic) NSString * titlecontents;
#property (weak, nonatomic) IBOutlet UILabel * titlelabel;
#property (strong, nonatomic) NSArray *arrayVidSrc;
#end
Implement the method - (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender. The sender is the cell that was clicked. You can then call something like [self.tableView indexPathForCell:sender] to get the cell address and use the row of the returned index path to pick the video out of your array.
The new view controller that will be shown when the segue finishes is available within the prepareForSegue:: method as [segue destinationViewController] and you can pass it whatever it will need.
I am building a simple app with a custom bar tab which loads the content of the ViewController from a UITableView located in another ViewController.
However, every time I try to scroll on the tableview, I get an exc_bad_access error. I enabled NSzombies and guard malloc to get more info on the issue.
In the console I get:
"message sent to deallocated instance 0x19182f20"
and after profiling I get:
# Address Category Event Type RefCt Timestamp Size Responsible Library Responsible Caller
56 0x19182f20 FirstTabBarViewController Zombie -1 00:16.613.309 0 UIKit -[UIScrollView(UIScrollViewInternal) _scrollViewWillBeginDragging]
Here is a bit of the code of the ViewController in which the error occurs:
.h file:
#import <UIKit/UIKit.h>
#import "DataController.h"
#interface FirstTabBarViewController : UIViewController <UITableViewDelegate, UITableViewDataSource> {
IBOutlet UITableView* tabBarTable;
}
#property (strong, nonatomic) IBOutlet UIView *mainView;
#property (strong, nonatomic) IBOutlet UITableView *tabBarTable;
#property (nonatomic, strong) DataController *messageDataController;
#end
.m file:
#import "FirstTabBarViewController.h"
#import "DataController.h"
#interface FirstTabBarViewController ()
#end
#implementation FirstTabBarViewController
#synthesize tabBarTable=_tabBarTable;
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (void)awakeFromNib
{
[super awakeFromNib];
self.messageDataController=[[DataController alloc] init];
}
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return 1;
}
- (NSInteger) tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{
return [self.messageDataController countOfList];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = #"mainCell";
UITableViewCell *cell = [tableView
dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil){
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
};
NSString *expenseAtIndex = [self.messageDataController
objectInListAtIndex:indexPath.row];
[[cell textLabel] setText:expenseAtIndex];
return cell;
}
- (BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath
{
// Return NO if you do not want the specified item to be editable.
return NO;
}
#end
This FirstTabBarViewController is loaded in the MainViewController with the following custom segue:
#import "customTabBarSegue.h"
#import "MainViewController.h"
#implementation customTabBarSegue
-(void) perform {
MainViewController *src= (MainViewController *) [self sourceViewController];
UIViewController *dst=(UIViewController *)[self destinationViewController];
for (UIView *view in src.placeholderView.subviews){
[view removeFromSuperview];
}
src.currentViewController =dst;
[src.placeholderView addSubview:dst.view];
}
#end
The Datacontroller class is just a simple NSMutableArray containing strings.
I am using ARC so I don't understand where the memory management error comes from. Does anybody have a clue?
Any help much appreciated ;)
Thanks!!
Ok... Thank you for the code sample...
See UIStoryboardSegue documentation, when you implement perform in your customTabBarSegue, you're responsible for setting, in the end, the correct relationship between your 2 viewControllers.
You have 2 possibilities:
setting dst as a modal child (then src is presentingViewController of dst), adding this code at the end of perform: [src presentViewController:dst animated:NO completion:nil];
setting dst as a child viewController of src - adding this code : [src addChildViewController:dst];
at the end of perform, but then, you have to remove it somewhere, or remove other childs in the same method....
Here's an implementation
#implementation customTabBarSegue
-(void) perform {
MainViewController *src= (MainViewController *) [self sourceViewController];
UIViewController *dst=(UIViewController *)[self destinationViewController];
for (UIView *view in src.placeholderView.subviews){
[view removeFromSuperview];
}
src.currentViewController =dst;
[src.placeholderView addSubview:dst.view];
// this container only show 1 viewController at a time, so we can remove previous ones
for (UIViewController *vc in src.childViewControllers) {
[vc.view removeFromSuperview];
[vc removeFromParentViewController];
}
//then add the new View controller as child
[src addChildViewController:dst];
}
#end
Anyway, you should definitively look more into UIViewController containment...