ios how can access and modify variable from diffent class? - iphone

I have the following:
Class 1:
.h file:
#interface class1 : UIViewController
#property (assign,nonatomic) int number;
.m file:
- (void)viewDidLoad
{
[super viewDidLoad];
number=1;
}
Class2:
.h file:
#interface class2 : UIView{
class1 *Controller;
}
#property (retain,nonatomic) class1 *controller;
but if access the number variable from anywhere in the second class the value is 0 any of you knows why?

Is the class already open and retained somewhere (i.e. your navigation stack)? If so you can then safely access and modify variables because they are already initialized. If not that's probably why you're getting 0 returned.
Another way is to create and maintain a data singleton that all view controllers can draw data from easily and you can then reference that data singleton to modify and change values.
Assuming the view controller is already initialized and active you can then do something like this:
MyViewController *vc = [[MyViewController alloc] init];
[vc setValue:#"100"];

You can use appDelegate method to access the variable from some other class,
example,
in your class2:
.m file
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
appDelegate = (AppDelegate *)[UIApplication sharedApplication].delegate;
Controller = appDelegate.viewControllerClass1;
}
return self;
}
in AppDelegate Class, .m
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
self.window = [[[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]] autorelease];
// Override point for customization after application launch.
self.viewControllerClass1 = [[[Class1 alloc] init] autorelease];
NavigationController=[[UINavigationController alloc]initWithRootViewController:self.viewControllerClass1];
[self.window makeKeyAndVisible];
return YES;
}

Related

NSLog returns (null) when logging string from another view controller

I posted a question earlier about the same thing, but now I have made a simple project to show what I am doing, so the problem can be found easier.
I have two viewControllers, one is called ViewController and the other SecondViewController.
I tried sending a NSString called testy to a viewController and logging it, but it returned null.
Here is my code trying to send the string from viewController to secondViewController
ViewController.m
#import "ViewController.h"
#import "SecondViewController.h"
#interface ViewController ()
#end
#implementation ViewController
#synthesize cellName;
- (void)viewDidLoad
{
[super viewDidLoad];
cellName = #"testy";
SecondViewController *obj = [[SecondViewController alloc] init];
obj.cellName2 = self.cellName;
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
#end
ViewController.h
#import <UIKit/UIKit.h>
#interface ViewController : UIViewController {
}
#property(nonatomic,retain) NSString *cellName;
#end
SecondViewController.m
#import "SecondViewController.h"
#import "ViewController.h"
#interface SecondViewController ()
#end
#implementation SecondViewController
#synthesize cellName2;
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
}
- (void)viewDidAppear:(BOOL)animated {
NSLog(#"%#",cellName2);
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
#end
SecondViewController.h
#import <UIKit/UIKit.h>
#interface SecondViewController : UIViewController {
}
#property(nonatomic,retain) NSString *cellName2;
#end
Edit
I would like to say that my storyboard has two viewController that each have a button. Each button modally brings you to the other view.
Are you sure viewDidLoad is being called? I think it's not called until the view is loaded. I don't think it's called after an alloc init. Also you are setting the string in obj 2 after init. Even if what you are thinking is correct, the 'viewDidLoad' method may be called before the string is being set.
If you want a variable set on init you need to override viewController 2's init method to something like initWithMyVariable then the var will be set on init.
From: Passing Data between View Controllers
Passing data forward to a view controller from another view controller. You would use this method if you wanted to pass an object/value from one view controller to another view controller that you may be pushing on to a navigation stack.
For this example we will have ViewControllerA and ViewControllerB
To pass a BOOL value from ViewControllerA to ViewControllerB we would do the following.
in ViewControllerB.h create a property for the BOOL
#property(nonatomic) BOOL *isSomethingEnabled;
in ViewControllerA you need to tell it about ViewControllerB so use an
import "ViewControllerB.h"
Then where you want to load the view eg. didSelectRowAtIndex or some IBAction you need to set the property in ViewControllerB before you push it onto nav stack.
ViewControllerB *viewControllerB = [[ViewControllerB alloc] initWithNib:#"ViewControllerB" bundle:nil];
viewControllerB.isSomethingEnabled = YES;
[self pushViewController:viewControllerB animated:YES];
This will set isSomethingEnabled in ViewControllerB to BOOL value YES.
It might be worth for all who read this article to mention working patterns passing variables between two views:
Options:
Use global variable: SO answer
Use delegation pattern: SO answer
Use notification infrastructure: article
Persist the value in app's userdefault storage, then read when you need : SO answer
For this particular situation it might be better not to create secondviewcontroller in the firstviewcontroller's viewdidload, but to keep the cellName until that point when a user action happens (eg. button press) and then in that method you just set the newly created secondviewcontroller's cellName2 property.
SecondViewController *secondViewController = [[SecondViewController alloc] initWithNibName:#"second" bundle:nil];
secondViewController.cellName = self.cellName;
I've tested and it is properly logging the value in secondviewcontroller's viewdidload.
Instead of doing: cellName = #"testy"; You should Call:
self.cellName = #"testy";
Also, When you alloc and init in:
SecondViewController *obj = [[SecondViewController alloc] init];,
the viewDidLoad() for secondViewController is called right at that time and you are initializing it's iVar later in the line obj.cellName2 = self.cellName;
That's why you are having NSLOG as null.
Print the NSLOG in viewWillAppear() of secondViewController and you will see the right value this time.
-Create a initialization method for second view controller to pass the variable..
in secondview controller
.h file
add init method
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil cellString(NSString* )cellName;
and .m file
-(id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil cellString(NSString* )cellName{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
cellName2=cellName;
}
return self;
}
and in ViewController.m for initialization
SecondViewController *obj = [[SecondViewController alloc] initWithNibName:#"SecondViewController" bundle:nil cellString:self.cellName];
This should work...
Best of luck
In viewcontroller.m you have the following in viewDidLoad:
..
..
SecondViewController *obj = [[SecondViewController alloc] init];
obj.cellName2 = self.cellName;
}
The SecondViewController "obj" is never being presented before the end of viewDidLoad, hence NSLog printing null.
If you are wanting to pass a value to SecondViewController via a storyboard, you will need to use the prepareForSegue method. A good example of using it can be found here.

iPhone application accessing data values from different classes

I have 4 classes i.e views in my application. Class A, having variable a and b.
After clicking on button which is on view A of class A it leads to class B, which is table view controller. Then class B leads to class C. then class C leads to class D.
Now i want to access values of a and b of class A into class D. I tried it with NSNotification but not succeeded.
Please suggest.
I tried with NSNotification:
i tried with NSNotification like Class A---
-(IBAction) selectButton:(id) sender{
NSString * a = [NSString stringWithFormat:#"Manjinder singh"];
NSDictionary * dict = [NSDictionary dictionaryWithObject:a forKey:#"1"];
[[NSNotificationCenter defaultCenter] postNotificationName:#"sendMessage" object:self userInfo:dict];
}
Then Class D----
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(sendMessage:) name:#"sendMessage" object:nil];
}
return self;
}
-(void)sendMessage:(NSNotification *)notification{
A *dil=[[A alloc] init];
nslog(#"dil.a");
NSLog(#"USERINFO:MyUserInfo (its a dictionary):%#",[[notification userInfo] valueForKey:#"1"]);
}
This is the rendom try but basically i want to show variable a and b of class A into class D.
Update:------------
MyCoolViewController.h// a class where data send from
#protocol MyCoolViewDelegate;
#interface MyCoolViewController : UIViewController {
id <MyCoolViewDelegate> delegate;//
}
#property (nonatomic, assign) id delegate;//
#end
#protocol MyCoolViewDelegate <NSObject>//
-(void)sendAStringToAnotherView:(NSString*)string;
#end
MyCoolViewController.m
-(void)viewDidLoad{
[delegate sendAStringToAnotherView:#"this is a string"];
}
firstViewController.m //a class where data sent
-(void)viewDidLoad{
MyCoolViewController *myViewControllerPointer=[[MyCoolViewController alloc] init];
myViewControllerPointer.delegate = self;//
}
-(void)sendAStringToAnotherView:(NSString*)string
{
//displays the string as console output
NSLog(#"plzzzzzz show data",string);
}
value of string is not passed to this class because it is not showing in NSLog output.
UPDATED 2---
MyCoolViewController.m
#import “MyCoolViewController.h”
#import "firstViewController.h"
#implementation MyCoolViewController
#synthesize label1,sttr;
#synthesize delegate;//
-(IBAction) selectButton:(id) sender{
if (curri==nil) {
curri=[[CurrancyViewController alloc] initWithNibName:nil bundle:nil];
[self.navigationController pushViewController:curri animated:YES];
}
curri=nil;
//CHECK ThIS [curri release];
}
- (void)viewDidLoad
{
[delegate sendAStringToAnotherView:#"this is a string"];
self.view.backgroundColor = [UIColor colorWithPatternImage:[UIImage imageNamed:#"background1.png"]];
[super viewDidLoad];
}
- (BOOL)shouldAutorotateToInterfaceOrientation: (UIInterfaceOrientation)interfaceOrientation
{
// Return YES for supported orientations
return (interfaceOrientation == UIInterfaceOrientationPortrait);
}
#end
Can you give more context about what specifically you are trying to achieve? It sounds like you want to pass data between several UIViewControllers. Here is how to set up a delegate for one of your view controllers:
#import <UIKit/UIKit.h>
#protocol MyCoolViewControllerDelegate;
#interface MyCoolViewController : UIViewController {
id <MyCoolViewControllerDelegate> delegate;
}
#property (nonatomic, assign) id delegate;
#end
#protocol MyCoolViewControllerDelegate <NSObject>
-(void)sendAStringToAnotherView:(NSString*)string;
#end
Then you will should synthesize the delegate
#synthesize delegate;
and then when you want to pass data to, lets say a parent view, call this function:
[delegate sendAStringToAnotherView:#"this is a string"];
In the other view controller, wherever you instantiated the instance of this UIViewController, you need to set that self as the delegate;
myViewControllerPointer.delegate = self;
and then implement the delegate function in the parent view controller.
-(void)sendAStringToAnotherView:(NSString*)string
{
//displays the string as console output
NSLog(string);
}
The fact that you need communicate between views like this could possibly mean that there is a more efficient means of structuring your app. Can't say for sure without more info.
Try and use this template to add a delegate to your own app.
You could use delegation here
D would become the delegate of A, and when you click the button, A sends a message to D with the variables as arguments and D responds by performing a method.

Why does my class variable in my Application Delegate not get instantiated?

This issue has been bugging me for a while now and somehow I cannot find what I'm doing wrong. I must say I am new to Objective-C and Xcode.
So the issue is that I try to declare an instance variable (NSMutableArray) but for some reason the init function is NEVER reached. The variable is always NULL.
So I have a class named PropertyProvider which contains a NSMutableArray named "properties".
#interface PropertyProvider : NSObject {
NSMutableArray *properties;
}
#property (nonatomic, retain) NSMutableArray *properties;
..
#end
I then instantiate this NSMutableArray in the init method of this PropertyProvider class as the following:
#implementation PropertyProvider
#synthesize properties;
- (id) init {
self = [super init];
NSLog(#"Instantiating PropertyProvider");
if (self) {
properties = [[NSMutableArray alloc] init];
}
return self;
}
.. more code ..
#end
In my Application delegate I try to instantiate the PropertyProvider as "prp":
#implementation MyAppDelegate
#synthesize prp = _prp;
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
// Override point for customization after application launch.
[[_prp init] alloc];
[self.window makeKeyAndVisible];
return YES;
}
.. more code ..
- (void)dealloc
{
[_prp release];
[super dealloc];
}
But thus, for some reason it never reaches the init method of my PropertyProvider. Why o why?!
Thanks for your help!
The correct way of initializing _prp as an instance of PropertyProvider would be,
_prp = [[PropertyProvider alloc] init];
Since _prp is an instance variable, it is nil by default and hence messages to it don't do anything which is the reason why you're not getting any errors.

- (void)dealloc Question

Can you tell me if the following code is 100% correct? Expecially the dealloc section
FirstViewController.h
#import <UIKit/UIKit.h>
#import "SecondViewController.h"
#class SecondViewController
#interface FirstViewController : UIViewController
{
SecondViewController *SecondController;
}
- (IBAction)SwitchView;
#property (nonatomic, retain) IBOutlet SecondViewController *SecondController;
#end
FirstViewController.m
#import "FirstViewController.h"
#implementation FirstViewController
#synthesize SecondController;
- (IBAction)SwitchView
{
SecondController = [[SecondViewController alloc] initWithNibName:#"SecondViewController" bundle:nil];
SecondController.modalTransitionStyle = UIModalPresentationFullScreen;
[self presentModalViewController:SecondController animated:YES];
[SecondController release];
}
/// OTHER CODE HERE ///
- (void)dealloc
{
[SecondController release];
[super dealloc];
}
#end
Thanks!
No it is not correct. You are sending the release message to a pointer in dealloc, but the pointer may or may not point to the SecondController anymore. This may lead to some very weird bugs, typically random objects being released.
In objective-c terms, your class doesn't retain (think "own") the SecondController, so it should not try to release it in the first place on dealloc.
To claim and release ownership the correct way, make it so:
- (IBAction)SwitchView
{
self.SecondController = [[[SecondViewController alloc]
initWithNibName:#"SecondViewController" bundle:nil] autorelease];
self.SecondController.modalTransitionStyle = UIModalPresentationFullScreen;
[self presentModalViewController:self.SecondController animated:YES];
}
/// OTHER CODE HERE ///
- (void)dealloc
{
self.SecondController = nil;
[super dealloc];
}
This will also protect you from any other stuff happening between SwitchView and dealloc. (as long as that stuff follows the rules and uses self.SecondController = ... to change the property)
In SwitchView the alloc/autorelease sequence makes that your routine keeps ownership for the length of the routine (and a little beyond). The self.SecondController = part makes sure that your class retains the SecondController object, since you declared it (nonatomic,retain).
You should use the property setter to assign SecondController.
I suggest you only alloc/init that view controller once, then in SwitchView show it:
#import "FirstViewController.h"
#implementation FirstViewController
- (id)initWithNibName:(NSString *)nibName bundle:(NSBundle *)nibBundle {
if((self = [super initWithNibName:nibName bundle:nibBundle])) {
self.SecondController = [[[SecondViewController alloc] initWithNibName:#"SecondViewController" bundle:nil] autorelease];
SecondController.modalTransitionStyle = UIModalPresentationFullScreen;
}
return self;
}
- (IBAction)SwitchView
{
[self presentModalViewController:SecondController animated:YES];
}
/// OTHER CODE HERE ///
- (void)dealloc
{
[SecondController release];
[super dealloc];
}
#end
This way, you only actually create that SecondController view controller once, as opposed to creating it every time -SwitchView is invoked.

Load different initial view based on application preferences?

I have a preference that, when set, forces my application to perform some synchronization on startup.
Can I use IB to display a different initial view based on this setting?
Is there a standard way to enable this behavior?
Assuming you have a property on your app delegate that is set during your synchronization, in the initial view controller's initWithNibNamed: method check the value synced by the app delegate and load the appropriate nib by calling [super initWithNibNamed:#"thisNibInsteadOfThatNib"];
EDIT: Show code to launch a different view depending on some condition at launch
// AppDelegate.h
#import <UIKit/UIKit.h>
#interface AppDelegate : NSObject <UIApplicationDelegate>
{
UIWindow *window;
UIViewController *firstViewController;
}
#property {nonatomic, retain} UIWindow *window;
#end
// AppDelegate.m
#import AppDelegate.h
#import ViewControllerOne.h
#import ViewControllerTwo.h
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
BOOL shouldLoadViewOne = \\ some value from preferences
if (shouldLoadViewOne) {
firstViewController = [[ViewOneController alloc] initWithNibName:#"ViewOneController" bundle:nil];
} else {
firstViewController = [[ViewTwoController alloc] initWithNibName:#"ViewTwoController" bundle:nil];
}
UINavigationController *navController = [[UINavigationController alloc] initWithRootViewController:firstViewController];
[window addSubView:[navController view]];
[window makeKeyAndVisible];
return YES;
}
EDIT 2:
Make use of NSClassFromSting() and save the name of the firstViewController to load in the preferences.
// AppDelegate.h
#import <UIKit/UIKit.h>
#interface AppDelegate : NSObject <UIApplicationDelegate>
{
UIWindow *window;
id firstViewController;
}
#property {nonatomic, retain} UIWindow *window;
- (NSString *)firstViewControllerName;
#end
// AppDelegate.m
#import AppDelegate.h
#import ViewControllerOne.h
#import ViewControllerTwo.h
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
NSString *viewControllerName = [self firstViewControllerName];
firstViewController = [[NSClassFromString(viewControllerName) alloc] initWithNibName:viewControllerName bundle:nil];
UINavigationController *navController = [[UINavigationController alloc] initWithRootViewController:firstViewController];
[window addSubView:[navController view]];
[window makeKeyAndVisible];
return YES;
}
- (NSString *)firstViewControllerName
{
NSString *defaultViewController = #"ViewOneController";
NSString *savedFirstViewController = // string retrieved from preferences or other persistent store
if (!savedFirstViewController)
return defaultViewController;
return savedFirstViewController;
}