UISplitView, Receiving Semantic Issues in setting up delegates - ios

I've been following Big Nerd Ranch's iOS Programming Guide (3rd Ed.) to set up my Xcode project which displays a list of my company's products and then a detailed view for each.
I got the app working swimmingly the way I need it to, but I started running into trouble when I tried to fancy up the user experience. Adding a UISplitViewController for iPad has caused me no end of head aches and wasted afternoons.
At the moment I am getting semantic issues reported on my delegate-related code. One in DetailViewController.h and the other in ListViewController.m.
I'll sum up my intent for this code before I post it, but in my inexperience I may miss some subtleties:
AppDelegate allocates UITableViewController (ListViewController class), and UIViewController (DetailViewController class) and then checks for an iPad. If an iPad, it creates a UISplitViewController using an array of the two views. Otherwise it loads ListViewController as the master view.
Before I tried to create the delegate relationship between the two views, the app was building successfully but the iPad UISplitViewController loaded only an empty detail view.
The iphone loaded ListViewController, then selecting a row displayed an empty detail view (DetailViewController). When you return to the TableView, and select the same or another table cell, the correct information would then load into DetailView. This led me to believe that the initial instance of the TableView was not passing on the selection correctly, but that returning to it (reallocating it?) would correct the problem. I was hoping the delegate setup would fix that. Since I can't get that part working I can't test that theory. I just figured I'd mention it.
I've looked around as much as I know how to (the right keywords and search terms elude me) with regards to UISplitViewController questions and tutorials, but they all vary greatly from what I've already set up in my project, either in the behavior of the app or the overall structure of the code. I'd rather not have to start over when I seem to be so close.
I've opened up the BigNerdRanch sample code (which does work) and, as I said, the only differences seem related to the way I want to display my information. At this point I need some help, please, to find what I'm doing wrong.
Thanks in advance!
AppDelegate.m:
#import "ProductFeedAppDelegate.h"
#import "ListViewController.h"
#import "DetailViewController.h"
#implementation ProductFeedAppDelegate
#synthesize window = _window;
#synthesize managedObjectContext = _managedObjectContext;
#synthesize managedObjectModel = _managedObjectModel;
#synthesize persistentStoreCoordinator = _persistentStoreCoordinator;
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
ListViewController *lvc = [[ListViewController alloc] initWithStyle:UITableViewStylePlain];
UINavigationController *masterNav = [[UINavigationController alloc] initWithRootViewController:lvc];
DetailViewController *dvc = [[DetailViewController alloc] init];
[lvc setDetailViewController:dvc];
if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) {
UINavigationController *detailNav = [[UINavigationController alloc] initWithRootViewController:dvc];
NSArray *vcs = [NSArray arrayWithObjects:masterNav, detailNav, nil];
UISplitViewController *svc = [[UISplitViewController alloc] init];
//set delegate
[svc setDelegate:dvc];
[svc setViewControllers:vcs];
[[self window] setRootViewController:svc];
} else {
[[self window] setRootViewController:masterNav];
}
self.window.backgroundColor = [UIColor whiteColor];
[self.window makeKeyAndVisible];
return YES;
}
//... trimmed out some template code to spare you
#end
`
ListViewController.h:
#import <Foundation/Foundation.h>
#import "ProductItemCell.h"
//#import "ItemStore.h"
#import "DetailViewController.h"
#class DetailViewController;
#class RSSChannel;
#interface ListViewController : UITableViewController
{
RSSChannel *channel;
}
#property (nonatomic, strong) DetailViewController *detailViewController;
-(void)fetchEntries;
#end
//A new protocol named ListViewControllerDelegate
#protocol ListViewControllerDelegate
//Classes that conform to this protocol must implement this method:
- (void)listViewController:(ListViewController *)lvc handleObject:(id)object;
#end
ListViewController.m:
#import "ListViewController.h"
#import "RSSChannel.h"
#import "RSSItem.h"
#import "DetailViewController.h"
#import "ContactViewController.h"
#import "FeedStore.h"
#implementation ListViewController
#synthesize detailViewController;
- (void)transferBarButtonToViewController:(UIViewController *)vc
{
// Trimming Code
}
- (id)initWithStyle:(UITableViewStyle)style
{
// Trimming Code
}
- (void)showInfo:(id)sender
{
// Create the contact view controller
ContactViewController *contactViewController = [[ContactViewController alloc] init];
if ([self splitViewController]) {
[self transferBarButtonToViewController:contactViewController];
UINavigationController *nvc = [[UINavigationController alloc]
initWithRootViewController:contactViewController];
// Create an array with our nav controller and this new VC's nav controller
NSArray *vcs = [NSArray arrayWithObjects:[self navigationController],
nvc,
nil];
// Grab a pointer to the split view controller
// and reset its view controllers array.
[[self splitViewController] setViewControllers:vcs];
// Make contact view controller the delegate of the split view controller
[[self splitViewController] setDelegate:contactViewController];
// If a row has been selected, deselect it so that a row
// is not selected when viewing the info
NSIndexPath *selectedRow = [[self tableView] indexPathForSelectedRow];
if (selectedRow)
[[self tableView] deselectRowAtIndexPath:selectedRow animated:YES];
} else {
[[self navigationController] pushViewController:contactViewController
animated:YES];
}
// Give the VC the channel object through the protocol message
// [channelViewController listViewController:self handleObject:channel];
}
- (void)viewDidLoad
{
// Trimming Code
}
- (NSInteger)tableView:(UITableView *)tableView
numberOfRowsInSection:(NSInteger)section
{
return [[channel items] count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView
cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
// Trimming Code
}
- (void)fetchEntries
{
// Trimming Code
}
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
if (![self splitViewController])
[[self navigationController] pushViewController:detailViewController animated:YES];
else {
[self transferBarButtonToViewController:detailViewController];
// We have to create a new navigation controller, as the old one
// was only retained by the split view controller and is now gone
UINavigationController *nav =
[[UINavigationController alloc] initWithRootViewController:detailViewController];
NSArray *vcs = [NSArray arrayWithObjects:[self navigationController],
nav,
nil];
[[self splitViewController] setViewControllers:vcs];
// Make the detail view controller the delegate of the split view controller
[[self splitViewController] setDelegate:detailViewController];
}
RSSItem *item = [[channel items] objectAtIndex:[indexPath row]];
// Next line reports: No visible #interface for 'DetailViewController' declares the selector 'listViewController:handleObject:'
[detailViewController listViewController:self handleObject:item];
}
#end
DetailViewController.h:
#import <UIKit/UIKit.h>
#import <Foundation/Foundation.h>
#import "ListViewController.h"
#class RSSItem;
#class Reachability;
#interface DetailViewController : UIViewController <ListViewControllerDelegate> // Cannot find protocol declaration for 'ListViewControllerDelegate'
{
__weak IBOutlet UILabel *nameField;
__weak IBOutlet UITextView *descriptField;
__weak IBOutlet UIImageView *imageView;
__weak IBOutlet UITextView *introtextField;
__weak IBOutlet UIButton *dsButton;
__weak IBOutlet UIButton *aeButton;
__weak IBOutlet UIButton *imButton;
}
-(BOOL)reachable;
#property (nonatomic, strong) RSSItem *item;
#property (nonatomic, strong) UIImage *productImage;
#end
DetailViewController.m:
#import "DetailViewController.h"
#import "RSSItem.h"
#import "RSSChannel.h"
#import "Reachability.h"
#interface DetailViewController ()
#end
#implementation DetailViewController
- (void)listViewController:(ListViewController *)lvc handleObject:(id)object
{
//RSSItem *item = object; //This was in the example code but if left in the next line reported "Local declaration of 'item' hides instance variable"
// Validate the RSSItem
if (![item isKindOfClass:[RSSItem class]])
return;
[self setItem:item];
[[self navigationItem] setTitle:[item name]];
[nameField setText:[item name]];
[descriptField setText:[item descript]];
[introtextField setText:[item introtext]];
}
#synthesize item;
- (BOOL)reachable{
// Trimming Code
}
- (void)viewDidLoad
{
[super viewDidLoad];
[[self view] setBackgroundColor:[UIColor whiteColor]];
}
- (void)viewWillAppear:(BOOL)animated
{
if (item){
[super viewWillAppear:animated];
[nameField setText:[item name]];
[descriptField setText:[item descript]];
[introtextField setText:[item introtext]];
// Trimming Code (all the stuff that looks for this or that value and acts upon it)
} else {
// The following appears in the log:
NSLog(#"There's no item selected");
}
}
#end

I think you are running into a problem with the compiler getting confused by having several
#import "DetailViewController.h"
If you remove this import from your ListViewController.h and keep the
#class DetailViewController;
Then I think this will get rid of your compiler problems.
You probably need to add < UISplitViewControllerDelegate > to a couple of your other classes though. Looks like you are setting them as delegates on the split view but not adopting the protocol.

The delegate relationships were not set up 100% correctly. Here is how this was fixed.
In ListViewController.m, added a class extension:
#interface ListViewController() <UISplitViewControllerDelegate>
#end
In ListViewController.h, removed:
#import "DetailViewController.h"
In DetailViewController.h, changed line to:
#interface DetailViewController : UIViewController <ListViewControllerDelegate, UISplitViewControllerDelegate>
In ContactViewController.h, changed line to:
#interface ContactViewController : UIViewController <MFMailComposeViewControllerDelegate, UISplitViewControllerDelegate>
These things cleared all errors. This did not, as I'd hoped in my original post, correct the issue of my item not being passed to the detailViewController, as that problem was a result of using "item" instead of "object" in DetailViewController.m's handleObject statement.

Related

Adding object to nsmutablearray doesn't work and any added objects disappear from my tableview

Through delegation I created a view controller that takes the input from textfields and passes it back and adds it to an nsmutablearray, successfully adding a row for it. whenever i navigate away from the tableview my newly appended object just disappears. Here is some code to give you a better idea of what i might be doing wrong.
TableViewController.h -
#interface TableViewController : UITableViewController<UITableViewDelegate, UITableViewDataSource>
#property(strong,nonatomic)NSMutableArray *codeList;
#property(strong,nonatomic)NSMutableArray *codeArray;
#end
TableViewController.m -
#interface TableViewController ()
#end
#implementation MCTableViewController
#synthesize codeList;
#synthesize codeArray;
- (void)viewDidLoad {
[super viewDidLoad];
self.tableView.delegate = self;
self.tableView.dataSource = self;
self.codeList = [NSMutableArray arrayWithObjects:#"Array",
#"Pointer",
#"Class",
#"Protocol",
#"Delegate",
nil];
self.codeDescArray = [NSMutableArray arrayWithObjects:
#"Array Description",
#"Pointer Description",
#"Class Description",
#"Protocol Description",
#"Delegate Description",
nil];
)
In the same class I programmatically created a button that moves to the view where data is supposed to be passed back. code below. This is done through delegation.
- (void)addNewCodeButtonPressed {
AddNewCodeVC *addVC = [[AddNewCodeVC alloc] init];
addVC.dataDelegate = self;
UINavigationController *navBar = [[UINavigationController alloc]initWithRootViewController:addVC];
[self.navigationController presentViewController:navBar animated:YES completion:nil];
}
Here is where the delegate logic is created in AddNewCodeVC.h -
#import <UIKit/UIKit.h>
#import "TableViewController.h"
#class AddNewCodeVC;
#protocol addNewCellData <NSObject>
- (void)sendDataToTableView:(NSString*)code codeDesc: (NSString*)desc;
#end
#interface AddNewCodeVC : UIViewController<UITextFieldDelegate> {
__weak id dataDelegate;
}
#property(weak,nonatomic)id<addNewCellData>dataDelegate;
#property(strong,nonatomic)UITextField *codeTextfield;
#property(strong,nonatomic)UITextField *descTextfield;
#end
finally here is the AddNewCodeVC.m -
#import "AddNewCodeVC.h"
#interface AddNewCodeVC ()
#end
#implementation AddNewCodeVC
#synthesize dataDelegate;
- (void)viewDidLoad {
[super viewDidLoad];
self.codeTextfield.delegate = self;
self.descTextfield.delegate = self;
//Programmatically created both textfields, nothing special
}
//"saveNewCode" is action for another button i created
- (void)saveNewCode {
sendDataToTableView:self.codeTextfield.text codeDesc:self.descTextfield.text];
[self.dataDelegate sendDataToTableView:self.codeTextfield.text codeDesc:self.descTextfield.text];
NSLog(#"CODE: %#", self.codeTextfield.text);
NSLog(#"DESC: %#", self.descTextfield.text);
[self dismissViewControllerAnimated:YES completion:nil];
}
The code works but nsmutable array wont hold the passed values if i navigate away from the TableViewController. I think this is because my main view controller programmatically segues to the tableview controller and creates a new instance of it, so that might have some effect? I'll leave some code below just in case it is relevant.
MainviewController.m -
- (void) tableViewBtnPressed:(UIBarButtonItem *)sender {
TableViewController *tableVC = [[TableViewController alloc] init];
//This for another delegate I created, not relevant
tableVC.selectedDataDelegate = self;
UINavigationController *navBar = [[UINavigationController alloc]initWithRootViewController:tableVC];
[self.navigationController presentViewController:navBar animated:YES completion:nil];
}
Hopefully this code is enough to illustrate the problem, i hope someone has an idea whats going on with the NSMutableArray, and why it isn't holding any new objects that are passed into it, any help is appreciated.

Pushing UIViewController fails with "Application tried to push a nil view controller on target"

So I'm using a NavigationController to do all the navigation of my iOS App. On the main screen there is a 'plus button' to take an image, and on pressing this button the NavigationController pushes the 'CameraViewController' with the method 'displayCamera:'. There the user can take an image and it is supposed to be previewed by another UIViewController which is pushed by the function 'picTaken:'. However overtime I try to push this view controller I get the error "Application tried to push a nil view controller on target". I have no idea what is going wrong. Below is the NavigationController.h and the corresponding .m file
NavigationController.h
#import <UIKit/UIKit.h>
#import "CameraViewController.h"
#import "MainViewController.h"
#import "PictureCheckViewController.h"
#interface NavigationController : UINavigationController {
CameraViewController *camView;
MainViewController *mainView;
PictureCheckViewController *checkView;
}
- (void)displayCamera:(id)sender;
- (void)picTaken:(id)sender;
#end
NavigationController.m
#import "NavigationController.h"
#interface NavigationController () {
}
#end
#implementation NavigationController
- (void)viewDidLoad
{
[super viewDidLoad];
camView = [[CameraViewController alloc] init];
mainView = [[MainViewController alloc] init];
checkView = [[PictureCheckViewController alloc] init];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (void)displayCamera:(id)sender {
[self pushViewController:camView animated:YES];
}
- (void)picTaken:(id)sender {
[self pushViewController:checkView animated:YES];
}
#end
If you need anymore information please tell me.
I appreciate your time and help :)
I would recommend you use a lazy instantiation method.
Add a property :
#Property(nonatomic,strong) MainViewController *mainView;
#Property(nonatomic,strong) PictureCheckViewController *checkView;
and override the getters yourself:
-(MainViewController*) mainView {
if(!_mainView) {
_mainView = [[MainViewController alloc] init];
}
return _mainView;
}
And like wise for checkView.
-(PictureCheckViewController*) checkView {
if(!_checkView) {
_checkView = [[PictureCheckViewController alloc] init];
}
return _checkView;
}
then access using:
self.checkView
self.mainView
Aside from I believe fixing your problem, it would also avoid creation unless the resource is actually used.

How to initiate a view controller from another view controller?

I have a table view controller called StackViewController, this is where I hold a list of todo's that has been created in CreateViewController...
I have an NSString property in StackViewController called currentTarget that represent the first to do in the stack:
import <UIKit/UIKit.h>
#interface StackTableViewController : UITableViewController
#property (nonatomic, strong) NSString *currentTarget;
#end
This property holds the first NSString object in the table view, I get it like this:
#import "StackTableViewController.h"
#import "Target.h"
#import "CoreDataStack.h"
#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 *target = [self.fetchedResultController objectAtIndexPath:indexPath];
self.currentTarget = target.body;
}
Now, when I log into my home page which called HomeViewController I want to initiate the StackTableViewController and get its currentTatget property value...
I know that there are delegate to help you notify other views when a change has happened, but in my case I want to get this property value before even I have been in this page (StackTableViewController), because the HomeViewController is the first view controller that is loaded (my initial view controller) and I what to access this property when I was just logged in to the app and populate a label with it.
How should I do this?
I thought maybe something like this:
#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;
self.targetLabel.text = current;
}
But i'm missing something here...my label is not populated...
I think there is something with the views lifecycle.
i'm a newbie please help me to figure this out...thanks
Don't do anything to do with graphics in viewDidLoad. The earliest you want to do it is in viewWillAppear (most of the time) and occasionally you will need to do it in viewDidAppear.
Try the same code in viewWillAppear and it should work.
Oh right, since your other viewController is setup in viewDidLoad, you need to call
[stackTableViewController view] on your stackTableViewController after you alloc init it. Seems weird, but this actually works. This is because the StackTableViewController doesn't have its calculation done when you initialize it, it runs through it in it's viewDidLoad delegate.
- (void)viewDidLoad {
[super viewDidLoad];
StackTableViewController *vc = [[StackTableViewController alloc] init];
[vc view];
NSString *current = vc.currentTarget;
self.targetLabel.text = current;
}

UITableView's custom delegate doesn't get called when displayed from UIPopoverController

Hoping someone had to solve related issues .. this is driving me nuts :/
My UITableViewController implements a custom delegate method:
.h
#protocol folderDelegate
#required
- (void)folderViewDidSelectPlan:(NSString*)planId;
#end
#interface FolderViewController : UITableViewController
#property (nonatomic, assign) id delegate;
#end
.m
#implementation FolderViewController
#synthesize delegate;
...
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
NSDictionary *row = [self->resultsPlan objectAtIndex:indexPath.row];
if ([delegate respondsToSelector:#selector(folderViewDidSelectPlan:)]) {
[delegate folderViewDidSelectPlan:[row objectForKey:#"id"]];
}
}
In my iPad's MainView I'm displaying this UITableView via UIPopoverController:
#interface ProjectViewController ()<folderDelegate>
...
- (void) selectPlan:(UIBarButtonItem*)sender
{
if([self->popoverSelectPlanController isPopoverVisible]){
[self->popoverSelectPlanController dismissPopoverAnimated:YES];
}
FolderViewController *folder = [[FolderViewController alloc] initWithStyle:UITableViewStyleGrouped withInstallation:self->_installationId withProjectId:self->_projectId withParentFolderId:#""];
folder.delegate = self;
UINavigationController *folderNavView = [[UINavigationController alloc] initWithRootViewController:folder];
self->popoverSelectPlanController = [[UIPopoverController alloc] initWithContentViewController:folderNavView];
[self->popoverSelectPlanController presentPopoverFromBarButtonItem:sender permittedArrowDirections:UIPopoverArrowDirectionAny animated:YES];
}
And handling the delegate via:
- (void) folderViewDidSelectPlan:(NSString *)planId
{
NSLog(#"called");
}
However, folderViewDidSelectPlan never get's called - I'm really stuck here, hope anyone has an idea how to solve this.
Thanks a lot!
Try to change declaration of the property to:
#property (assign) id<folderDelegate> delegate;
And also use self.delegate instead of in your UITableViewController.m file every time instead of just delegate.
If you don't have to support iOS4 or less remove synthesise from UITableViewController.m.

Obj-C - How to pass data between viewcontrollers using a singleton?

Alright, so this is an extension to a question I asked last night. I have a little firmer grasp on how data can be passed between view controllers using various techniques. I wanted to go the MVC route, and creating a Singleton class seems the closest concept similar to MVC.
Basically I created a simple app with two View Controllers and a singleton class. I am trying to pass the value of a text field into a UILabel. For whatever reason it isn't working. This is what my code looks like.
ViewController.h
#import <UIKit/UIKit.h>
#import "Model.h"
#import "ViewController2.h"
#interface ViewController : UIViewController {
NSString *text2pass;
}
#property (weak, nonatomic) IBOutlet UITextField *tf;
#property (weak, nonatomic) IBOutlet UILabel *btn;
- (IBAction)go:(id)sender;
#end
ViewController.m
#import "ViewController.h"
#interface ViewController ()
#end
#implementation ViewController
#synthesize tf = _tf;
#synthesize btn = _btn;
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
NSString *tfstring = _tf.text;
NSLog(#"string = %#",tfstring);
}
- (void)viewDidUnload
{
[self setTf:nil];
[self setBtn:nil];
[super viewDidUnload];
// Release any retained subviews of the main view.
}
- (IBAction)go:(id)sender {
NSLog(#"btn pressed");
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:#"MainStoryboard" bundle:nil];
ViewController2 *vc2 = (ViewController2 *) [storyboard instantiateViewControllerWithIdentifier:#"home"];
text2pass = _tf.text;
[self passValues];
[self presentModalViewController:vc2 animated:YES];
}
-(void) passValues {
Model *model = [Model sharedModel];
model.passedText = text2pass;
}
#end
ViewController2.h
#import <UIKit/UIKit.h>
#import "ViewController.h"
#interface ViewController2 : UIViewController {
NSString *passedText;
}
#property (nonatomic)NSString *passedValue;
#property (weak, nonatomic) IBOutlet UILabel *lbl;
- (IBAction)back:(id)sender;
#end
ViewController2.m
#import "ViewController2.h"
#interface ViewController2 () {
NSString *passedtext;
}
#end
#implementation ViewController2
#synthesize lbl = _lbl;
#synthesize passedValue = _passedValue;
- (void)viewDidLoad
{
// do code stuff here
NSLog(#"passedText = %#",passedText);
_lbl.text = passedText;
[super viewDidLoad];
}
- (void)viewDidUnload
{
[self setLbl:nil];
[super viewDidUnload];
// Release any retained subviews of the main view.
}
- (IBAction)back:(id)sender {
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:#"MainStoryboard" bundle:nil];
ViewController *vc = (ViewController *) [storyboard instantiateViewControllerWithIdentifier:#"welcome"];
[self presentModalViewController:vc animated:YES];
}
#end
Model.h
#import <Foundation/Foundation.h>
#interface Model : NSObject {
NSString *passedText;
}
#property (nonatomic, strong) NSString* passedText;
+ (Model *) sharedModel;
#end
Model.m
#import "Model.h"
#implementation Model
#synthesize passedText = _passedText;
static Model *sharedModel = nil;
+ (Model *) sharedModel {
#synchronized(self){
if (sharedModel == nil){
sharedModel = [[self alloc] init];
}
}
return sharedModel;
}
#end
The project can be downloaded in its entirety from here http://chrisrjones.com/files/KegCop-Test.zip
If you know why the UILabel is not displaying the text field text let me know. Oh I pretty much followed this -> http://www.youtube.com/watch?v=ZFGgMPcwYjg&feature=plcp
Your addressing, and memory management is just plain... off. Firstly, there's absolutely no reason to create a singleton for this, but that's beside the point here.
Secondly, when declaring properties, (atomic, assign) is defaulted to if not otherwise specified, which means your string:
#property (nonatomic)NSString *passedValue;
is weak sauce, ripe for deallocation and destruction at a moments notice. Declare it copy, strong, or retain.
Thirdly, there's absolutely no reference to your singleton in the pushed view controller, yet you seem to have the belief that objects that are named the same in different classes retain their value (especially when #import'ed). Not so. You need to reference your singleton and pull the value of [Model sharedModel].passedText into that text field.
In fact, I fixed your sample in two lines:
//ViewController2.m
#import "ViewController2.h"
//actually import the singleton for access later
#import "Model.h"
#interface ViewController2 () {
NSString *passedtext;
}
#end
#implementation ViewController2
#synthesize lbl = _lbl;
#synthesize passedValue = _passedValue;
- (void)viewDidLoad
{
// do code stuff here
NSLog(#"passedText = %#",passedText);
//actually reference the singleton this time
_lbl.text = [Model sharedModel].passedText;
[super viewDidLoad];
}
- (void)viewDidUnload
{
[self setLbl:nil];
[super viewDidUnload];
// Release any retained subviews of the main view.
}
- (IBAction)back:(id)sender {
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:#"MainStoryboard" bundle:nil];
ViewController *vc = (ViewController *) [storyboard instantiateViewControllerWithIdentifier:#"welcome"];
[self presentModalViewController:vc animated:YES];
}
#end
Which yields this:
I wouldn't recommend using a Singleton as a good way to pass data around your application. Most apps are simple enough that this kind of central access is not necessary, and it usually creates a maintenance nightmare... but I don't think the fact that you're using a Singleton is actually important to getting your code working.
Assuming you have access to the data in ViewController1, in your case through the a Singleton instance of Model (which needs a more descriptive name), then all you have to do is pass through the data to ViewController2 when it is created and presented, which eliminates the need for a Singleton at all.
Once you create the controller, set the data you need, and then present the view controller - which is basically what you're doing anyway.
As to why it's not working: Is the view controller being presented, just not with the correct data? Or is there actually an issue presenting the controller at all? I would set a breakpoint in the go: action of ViewController1, make sure the data you expect is in the textfield, correctly populates the Model and that the value is correctly pulled out of the Model in ViewController2.
Unless you've removed some of the code, it looks like you correctly populate the Model property in ViewController1, but in ViewController2 you refer to a local ivar passedTextrather than pulling it from the model.
On a separate note, the way to go back from a presented modal view controller is usually to dismiss that controller, not to re-create the initial controller and present that over the top.

Resources