can't get a view controller property to another view controller - ios

i have 2 view controllers:
StackTableViewController.m:
#interface StackTableViewController () <NSFetchedResultsControllerDelegate>
#property (nonatomic, strong) NSFetchedResultsController *fetchedResultController;
#end
#implementation StackTableViewController
- (void)viewDidLoad {
[super viewDidLoad];
[self.fetchedResultController performFetch:nil];
NSIndexPath *indexPath = [NSIndexPath indexPathForItem:0 inSection:0];
Target *record = [self.fetchedResultController objectAtIndexPath:indexPath];
self.currentTarget = record.body;
}
HomeViewController.m
#import "HomeViewController.h"
#import "CreateViewController.h"
#import "StackTableViewController.h"
#interface HomeViewController ()
#property (strong, nonatomic) IBOutlet UILabel *targetLabel;
#end
#implementation HomeViewController
- (void)viewDidLoad {
[super viewDidLoad];
StackTableViewController *vc = [[StackTableViewController alloc] init];
NSString *current = vc.currentTarget;
// Do any additional setup after loading the view.
self.targetLabel.text = current;
}
but something wrong with the HomeViewController because it's not populating the label..
how can i solve it?
tnx

You should probably update the label's text within ViewWillAppear of the StackTableViewController
Also, is currentTarget set up in StackTableViewController's init method? If not, it won't be initialized and that would be why you're not getting anything in HomeViewController's label

Explanation
viewDidLoad is not called instead, or before the init! It's called sometime after the init method finishes.
What happens:
- (void)viewDidLoad {
[super viewDidLoad];
StackTableViewController *vc = [[StackTableViewController alloc] init]; // init is called on vc object
NSString *current = vc.currentTarget; // ViewDidLoad was not yet called on vc object!
self.targetLabel.text = current;
}
/// ViewDidLoad will be called on vc object sometime after leaving this method!
What happens is:
You call StackTableViewController *vc = [[StackTableViewController alloc] init]; which sends a message init to the object.
You don't have init method in your implementation so the init of superclass (UIViewController) is called. When you instantiate your ViewController it begins loading view. Only after it's done loading ViewDidLoad will be called.
Please read any article on ViewController's lifecycle .
Solution
Fastest solution to your problem: create a delegate in your table, and inform when it's done loading using delegates, like this:
Table view controller
#implementation StackTableViewController
{
id<TargetChangedDelegate> _myDelegate;
}
-(id)initWithDelegate:(id<TargetChangedDelegate>)delegate
{
_myDelegate= delegate;
}
- (void)viewDidLoad {
[super viewDidLoad];
[self.fetchedResultController performFetch:nil];
NSIndexPath *indexPath = [NSIndexPath indexPathForItem:0 inSection:0];
Target *record = [self.fetchedResultController objectAtIndexPath:indexPath];
self.currentTarget = record.body;
// inform your delegate
[_myDelegate targetChanged];
}
Home view controller
#interface HomeViewController () <TargetChangedDelegate>
#property (strong, nonatomic) IBOutlet UILabel *targetLabel;
#end
#implementation HomeViewController
- (void)viewDidLoad {
[super viewDidLoad];
StackTableViewController *vc = [[StackTableViewController alloc] initWithDelegate:self];
}
- (void)targetChanged
{
NSString *current = vc.currentTarget;
// Do any additional setup after loading the view.
self.targetLabel.text = current;
}

Related

Custom Delegate method is not getting called

I have set up custom delegate as follows, but delegate method is not getting called. I wonder what I am missing in my following implementation.
ComboSetViewController.h
#protocol ComboSetViewControllerDelegate <NSObject>
#required
- (void)comboSelected;
#end
#interface ComboViewController : UIViewController <UITableViewDelegate, UITableViewDataSource>
#property (nonatomic, weak) id <ComboSetViewControllerDelegate> comboSelectedDelegate;
#end
ComboSetViewController.m
- (IBAction)doneBtnClicked
{
selectedCombo.orderProductItemArray = comboOrderItemArray;
[comboSelectedDelegate comboSelected];
[self dismissViewControllerAnimated:YES completion:nil];
}
HomeViewController.h
#import "ComboViewController.h"
#interface HomeViewController : UIViewController<ComboSetViewControllerDelegate>
HomeViewController.m
- (void)viewDidLoad {
[super viewDidLoad];
ComboViewController *comboViewController = [[ComboViewController alloc] init];
comboViewController.comboSelectedDelegate = self;
}
// is not getting called
-(void)comboSelected
{
NSLog(#"Combo Selected");
}
EDIT: If I assign the delegate in the prepareSegue, then it works.
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
if ([[segue identifier] isEqualToString:#"isCombo"])
{
ComboViewController *vc = [segue destinationViewController];
// Assign self as the delegate for the child view controller
vc.comboSelectedDelegate = self;
}
}

ios custom delegate is null after second click in navigation controller

I have a custom UIWebView (EpubWebView), with a custom NSURLCache (EpubCache) for handling requests.
i created a custom delegate for handling request.
EpubCache.h
#protocol EpubCacheDelegate <NSObject>
#required
- (NSCachedURLResponse *)hadleRequest:(NSURLRequest *)request;
#end
#interface EpubCache : NSURLCache
#property (nonatomic, weak) id <EpubCacheDelegate> cacheDelegate;
#end
EpubCache.m
import "EpubCache.h"
#interface EpubCache ()
#end
#implementation EpubCache
- (NSCachedURLResponse *)cachedResponseForRequest:(NSURLRequest *)request
{
return [self.cacheDelegate hadleRequest:request];
}
#end
EpubWebView .h
#interface EpubWebView : UIWebView <UIWebViewDelegate, EpubCacheDelegate>
#property (strong, nonatomic) EpubCache *mLocalCache;
#end
EpubWebView.m
- (void) localInit
{
self.mLocalCache = [[EpubCache alloc] init];
self.mLocalCache.cacheDelegate = self;
[NSURLCache setSharedURLCache:self.mLocalCache];
}
- (NSCachedURLResponse *)hadleRequest:(NSURLRequest *)request
{
// return handled request
}
on the other hand i have a navigationcontroller with a tableview and the destination view controller have this webview.
when i ran the app and click on an item in tableview, everything is fine and delegate works as expected.
if i click back and click on other item in tableview, things goes wrong, the cachedResponseForRequest getting called but the hadleRequest wont, i checked and findout that the delegate is null!
i can not figure out what is happening here.
any help would be appreciated.
UPDATE 1
EpubWebView.m
- (id)init
{
self = [super init];
if (self)
{
[self localInit];
}
return self;
}
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if(self)
{
[self localInit];
}
return self;
}
- (id)initWithCoder:(NSCoder *)aDecoder
{
self = [super initWithCoder:aDecoder];
if(self)
{
[self localInit];
}
return self;
}
UPDATE 2
the segue of the tableview that bring up the view controller that contain EpubWebView
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
NSIndexPath *indexPath = [self.collectionView indexPathForCell:sender];
BookViewController *bookController = segue.destinationViewController;
bookController.mBook = booksList[indexPath.row];
}
and BookViewController.m
- (void)viewDidLoad
{
[super viewDidLoad];
mWebView = [[EpubWebView alloc] initWithFrame:self.mainView.frame];
[self.mainView addSubView:mWebView];
[mWebView setBook:self.mBook];
}
You need to make a few modifications. First, remove your "localInit" method, then create a new function in EPubWebView:
- (void) setCache: (EpubCache *)localCache
{
localCache.cacheDelegate = self;
}
Now, you can create and hold onto your cache in your BookViewController via these lines in the .m file:
#interface BookViewController ()
#property (strong, nonatomic) EpubCache *mLocalCache;
#end
and change your BookViewController's viewDidLoad method to look like:
- (void) viewDidLoad {
self.mLocalCache = [[EpubCache alloc] init];
// only need to do this once, at viewDidLoad time
[NSURLCache setSharedURLCache:self.mLocalCache ];
[super viewDidLoad];
mWebView = [[EpubWebView alloc] initWithFrame:self.mainView.frame];
[mWebView setCache:self.mLocalCache];
[self.mainView addSubView:mWebView];
[mWebView setBook:self.mBook];
}

Can't get one a table view data from another view controller

i'm trying to perform something pretty simple which is:
I have a home page view controller and a table view controller (separate controllers) which supports deleting cells.
In the home page I have a UILabel object which I want to populate with the first cell in the table view controller. So I figured what I need is to create an instance of my table view controller in my home page view controller and ask this information...but from some reason the object i'm getting from the table view controller called "currentTarget" is nil...(and it's not).
This is my HomeViewController: (just the relevant lines)
#import "StackTableViewController.h"
#interface HomeViewController ()
#property (strong, nonatomic) IBOutlet UILabel *homeLabel;
#end
#implementation HomeViewController
- (id)init {
self = [super initWithNibName:#"HomeViewController" bundle:nil];
if (self) {
// Do something
}
return self;
}
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view from its nib.
[self.navigationController setNavigationBarHidden:YES];
self.homeLabel.font = [UIFont fontWithName:#"Candara-Bold" size:40];
StackTableViewController *svc = [[StackTableViewController alloc] init];
self.homeLabel.text = svc.currentTarget;
}
This is my StackTableViewController.m: (just the relevant lines)
#import "StackTableViewController.h"
#import "Target.h"
#import "StackTableViewCell.h"
#import "HomeViewController.h"
#import "CoreDataStack.h"
#interface StackTableViewController () <NSFetchedResultsControllerDelegate>
#property (nonatomic, strong) NSFetchedResultsController *fetchedResultController;
#end
#implementation StackTableViewController
- (id)init {
self = [super initWithNibName:#"StackTableViewController" bundle:nil];
if (self) {
// Do something
}
return self;
}
- (void)viewDidLoad {
[super viewDidLoad];
self.navigationItem.rightBarButtonItem = self.editButtonItem;
[self.fetchedResultController performFetch:nil];
NSIndexPath *indexPath = [NSIndexPath indexPathForItem:0 inSection:0];
Target *current = [self.fetchedResultController objectAtIndexPath:indexPath];
self.currentTarget = current.body;
}
And also added this code in the prepare for segue method so the currentTarget will get updated coming back from segue:
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
[self.fetchedResultController performFetch:nil];
NSIndexPath *indexPath = [NSIndexPath indexPathForItem:0 inSection:0];
Target *current = [self.fetchedResultController objectAtIndexPath:indexPath];
self.currentTarget = current.body;
}
why my label won't show up :/?
tnx ahead
The problem is that your init method does not initialise either the fetched results controller or the currentTarget property. They are only initialised When you present that table view controller and the viewDidLoad method runs. If you move (or copy) these lines to your init method, it should work:
[self.fetchedResultController performFetch:nil];
NSIndexPath *indexPath = [NSIndexPath indexPathForItem:0 inSection:0];
Target *current = [self.fetchedResultController objectAtIndexPath:indexPath];
self.currentTarget = current.body;
In your StackTableViewController.m:
- (id)init {
self = [super initWithNibName:#"HomeViewController" bundle:nil];
if (self) {
[self.fetchedResultController performFetch:nil];
NSIndexPath *indexPath = [NSIndexPath indexPathForItem:0 inSection:0];
Target *current = [self.fetchedResultController objectAtIndexPath:indexPath];
self.currentTarget = current.body; }
return self;
}

How do you load video from an array in table detail view when the user clicks on the cell?

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.

Performing method on another UIViewController

I am using following code to set the text of a UILabel in SViewController, From another ViewController FViewController
SViewController *vc = [self.storyboard instantiateViewControllerWithIdentifier:#"SViewController"];
[vc setTextForLabel:[NSNumber numberWithInt:1];];
[self.navigationController pushViewController:vc animated:YES];
The setTextForLabel method:
-(void) setTextForLabel: (NSNumber *)text {
textLabel = [[UILabel alloc] init];
[textLabel setText:[NSString stringWithFormat:#"%#",[text stringValue]]];
NSLog(#"The text is %#", textLabel.text);
}
I have declared the property for textLabel in .h file is as follows:
#property (nonatomic, retain) IBOutlet UILabel *textLabel;
And I have also set the IBOutlet in storyboard.
Now in console I see "The text is 1", but the UI is not showing anything!
What am I doing wrong?
remove this line
textLabel = [[UILabel alloc] init];
Also, you need to link the UILabel on interface to your #property (nonatomic, retain) IBOutlet UILabel *textLabel;
Or you may add this label manually to view
textLabel = [[UILabel alloc] init];
[textLabel setText:[NSString stringWithFormat:#"%#",[text stringValue]]];
[self.view addSubView:textLabel];
First of all go put
[vc setTextForLabel:[NSNumber numberWithInt:1]];
after you push the vc.
In your xib/storyboard if your label has something written in it, remove it, leave it blank.
If that doesn't work ... leave the setText method before the push one (as you wrote it initialy) and create a NSNumber member that will hold your value and apply it in viewDidAppear like so
-(void) setTextForLabel: (NSNumber *)text{
numberValue = text; // declared in .h as NSNumber *numberValue (only make it a property if you need acces to it from outside your class)
}
- (void)viewDidAppear:(BOOL)animated {
[super viewDidAppear:animated]; //this is important
[textLabel setText:[NSString stringWithFormat:#"%#",[numberValue stringValue]]];
}
Your problem is linked to the view lifecycle of SViewController. When you call [.. setTextForLabel] you don't know if the controller has loaded its views (And thus your UILabel have a good chance of not being created yet)
What you should do is use a NSString property on your controller, set it with the desire text and assigned it to the UILabel in the viewDidLoad of SViewController.
in SViewController.h
#propery (strong, nonatomic) NSString *textToDisplay;
in SViewController.m
-(void)viewDidLoad
{
[super viewDidLoad];
// Here you know all Outlet are loaded and connected
textLabel.text = textToDisplay
}
I did like this
#import "FViewController.h"
#import "SViewController.h"
#interface FViewController ()
#end
#implementation FViewController
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
}
- (IBAction)do:(id)sender
{
SViewController *vc = [self.storyboard instantiateViewControllerWithIdentifier:#"SViewController"];
[self.navigationController pushViewController:vc animated:YES];
[vc setTextForLabel:[NSNumber numberWithInt:1]];
}
// in SViewController.h
#import <UIKit/UIKit.h>
#interface SViewController : UIViewController
#property (weak, nonatomic) IBOutlet UILabel *label;
-(void) setTextForLabel: (NSNumber *)text;
#end
// SViewController.m file
#import "SViewController.h"
#interface SViewController ()
#end
#implementation SViewController
#synthesize label;
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view.
}
-(void) setTextForLabel: (NSNumber *)text{
// label.text = [text stringValue];
NSLog(#"%#",label);
[label setText:[text stringValue]];
}
#end
also check your label properties in storyboard are properly set

Resources