Can't access class instance from another class - iphone

in my AppDelegate I have imported the header of a class I have created and propertied and syntesized an instance of it (in AppDelegate). Now I'm trying to access a method and a variable inside this instance from two other views. I'm relatively new to objective-c, but so far I've learned that if I do this:
AppDelegate *appdelegate = [AppDelegate new];
I will just get a fresh instance from the class inside AppDelegate, so if I set a variable from one view, I can't access it from the other. I've read that if I would do it this way:
AppDelegate *ap = (AppDelegate *)[[UIApplication sharedApplication] delegate];
It would allow me to access the existing instance. But it doesn't work.
Is the way I'm trying to do this totally wrong? Thanks a lot for your help!
UPDATE:
When I do this inside AppDelegate:
myClass.string = #"test";
NSLog(#"appDelegate: %#", myClass.string);
I get this:
appDelegate: (null)
UPDATE2:
I wrote #class AppDelegate; underneath the #import lines in the viewController, but still I can't access myClass. A main problem, which may be the cause why this isn't working from the views, is that I can't even access myClass from AppDelegate.
In AppDelegate.h I wrote:
#property (strong, nonatomic) testClass *myClass;
In AppDelegate.m:
#import "testClass.h"
#synthesize myClass;
This should be right, right?
myClass.h
#property (strong, nonatomic) NSString *string;
myClass.m
#synthesize string;
When I then try to access myClass from appDelegate, I write:
self.myClass.string = #"test";
NSLog(#"appDelegate: %#", self.myClass.string);
The result is:
appDelegate: (null)

I think you have to allocate and initialize the myClass
Write myClass = [MyClass alloc] init] in AppDelegate.m file

#import "AppDelegate"
and also write
#class AppDelegate;

Unless you haven't shown it, you're not allocating testClass and not assigning it to myClass. Objective-C is not like C++ or Java where you can simply declare a variable of a particular class type and have it instantiated on the stack. Each class you use must be instantiated, whether manually or through InterfaceBuilder. The exception is there are some classes provided by the various frameworks which have a single shared instance. Rather than allocating those classes, you simply ask for the shared instance. However, that's not the case here. It's your own class, so you need to allocate it.
It would look like:
myClass = [[testClass alloc] init];

Related

iOS - Set Model class to be delegate of another Model class

I have a CLLocationManager singleton which implements a protocol, so I can tell another model class (ServerConnection) that an updated location of the user has been found.
In my AppDelegate in the method, didFinishLaunching, I write
ServerConnection* serverConnection = [[ServerConnection alloc] init];
[LocationManager sharedLocationSingleton].delegate = serverConnection;
[[LocationManager sharedLocationSingleton] getUsersLocation];
This doesn't work and the delegate method in my ServerConnection class isn't called. However, if I try having my AppDelegate class be the listener, as in the following line, it works fine.
// self refers to AppDelegate
[LocationManager sharedLocationSingleton].delegate = self;
Here, my AppDelegate implements the required delegate method and the method is called when the user's location is updated, as it should.
Why is my above method failing, where I try to set the delegate to be serverConnection?
Tutorials online usually point to using a UIViewController or the AppDelegate as the "listener", but in my case, I want a separate model class to be the listener. How do I do that?
Below is my LocationManager singleton class with the protocol
#class LocationManager;
#protocol LocationManagerDelegate <NSObject>
#required
-(void)LocationManagerUpdated:(LocationManager*) locationManager
withValue:(CLLocation*) location;
#end
#interface LocationManager : NSObject <CLLocationManagerDelegate>
#property (strong, nonatomic) CLLocationManager* locationManager;
#property (strong, nonatomic) CLLocation* location;
#property (weak, nonatomic) id <LocationManagerDelegate> delegate;
+(LocationManager*)sharedLocationSingleton;
-(void) getUsersLocation;
#end
My header file for Server connection is.
#import <Foundation/Foundation.h>
#import "LocationManager.h"
#interface ServerConnection : NSObject <LocationManagerDelegate>
#end
This works when AppDelegate is set to be the listener, but not my model object ServerConnection. How do I fix this?
Thanks!
There should be no problem in doing what you are trying to do (i.e., having a non-controller class instance to act as a delegate).
This works when AppDelegate is set to be the listener, but not my model object ServerConnection.
Does your ServerConnection class implement the LocationManagerDelegate protocol? (I mean implement as opposed to just declare it in its interface).
Check the LocationManager method in charge for calling the delegate method (LocationManagerUpdated:) and add there a NSLog trace to check that the delegate object is correctly set when you try and send it the message.
EDIT:
ServerConnection* serverConnection = [[ServerConnection alloc] init];
[LocationManager sharedLocationSingleton].delegate = serverConnection;
[[LocationManager sharedLocationSingleton] getUsersLocation];
after you comment, it is clear that the issue stems from instantiating serverConnection in a stack variable and not in a property.
Your approach of making the delegate property a strong property is not correct since it leads to retain cycles. What you need to do is defining a strong serverConnection property in the class that executes the code I pasted above (the app delegate?).
If you don't mind my being rash, if you define the delegate as a strong property, what you are doing is fixing a bug by adding a second bug that hides the first one.
It looks like serverConnection is not retained anywhere and because delegate property is specified as weak, it is released and set to nil.
Check getUsersLocation method and see if delegate is nil at the moment you are trying to call LocationManagerUpdated:withValue:

Proper way to make variable accessible within entire .m file?

As you can tell, I'm new to Objective-C. I currently have a Singleton working, but I'm trying to use it throughout several methods within the same .m file.
Right now I use this to declare/instantiate the Singleton within a method:
GlobalData *globDat=[GlobalData getInstance];
Do I need to declare it within each method, or is there a way to do this at the top of the .m (or .h?) file so I can access it throughout the other methods?
Thanks...
(BTW I've tried placing the line of code shown above under my "#implementation" line, but I get an error: "Initializer element is not a compile-time constant" which I now know is because the line is not within a method.)
You can add a class extension, and store the global data in ivar, like this:
#interface MyClass() {
GlobalData *globDat;
}
#end
#implementation MyClass
-(id) init {
self = [super init];
if (self) {
globDat=[GlobalData getInstance];
}
return self;
}
#end
This will hide the globDat from the interface, and make it available throughout the methods you implement inside your implementation block of MyClass.
when u need a variable / object that is accessible to all methods in an implementation data, u need to declare it on the header file, and then synthesize it on the implementation file (note that u may need to import the GlobalData header)
so
in header (.h):
#class GlobalData;
#properties (nonatomic, strong) GlobalData *globDat;
and then at the implementation file (.m)
#import "blablabla.h"
#import "GlobalData.h"
#implementation blablabla
#synthesize globDat;
-(void)viewDidLoad
{
globDat = [GlobalData getInstance];
}
good luck

How to let one class change a variable (or object) in another class

I'm fairly new to programming in Objective-C. While I have been able to find my way, there now is an issue I cannot solve, which is either caused by a mistake I made or because I have a fundamental misunderstanding about classes.
Essentially, I want one class to change a variable (or object) in another class. Here is the code I have:
// LocationManager.h
#import <Foundation/Foundation.h>
#import <CoreLocation/CoreLocation.h>
#interface LocationManager : NSObject <CLLocationManagerDelegate> {
CLLocationManager *locationManager;
CLLocation *locationByCustomLocation;
}
#property (nonatomic, retain) CLLocation *locationByCustomLocation;
#end
Of course, there's a corresponding implementation file: LocationManager.m. It synthesizes the locationByCustomLocation variable.
The point is that from another class, I'd like to manipulate the locationByCustomLocation variable.
// viewCustomLocation.h
#import <UIKit/UIKit.h>
#interface viewCustomLocation : UIViewController <UITableViewDataSource, UITableViewDelegate> {
UITableView *tblLocation;
UITableViewCell *cell;
}
--
//viewCustomLocation.m
#import "viewCustomLocation.h"
#import "LocationManager.h"
#class LocationManager;
#implementation viewCustomLocation
#synthesize tblLocation;
#synthesize cell;
// some view related selectors here, but it boils down to this one:
- (void)dismissView:(id)sender
{
[self dismissModalViewControllerAnimated:YES];
LocationManager *locationManager = [[LocationManager alloc] init];
// I made sure with NSLog that the customLoc variable contains the expected data
CLLocation *customLoc = [[CLLocation alloc] initWithLatitude:place.coordinate.latitude longitude:place.coordinate.longitude];
[locationManager setLocationByCustomLocation:customLoc];
}
Now, if I use NSLog in LocationManager.m to see what's in the LocationByCustomLocation variable, I would expect the same data as in customLoc. Instead, the variable still seems empty.
I think the problem is that I created a copy of the LocationManager class, thus filling the LocationByCustomLocation variable in the copied class, rather than the original one, which is what I want. I can't figure out how to talk to the original LocationManager class.
I know of a few ways to work around this issue, but I would like to know how to achieve it this way to improve my fundamental understanding of the language.
Thanks for reading!
That's because you are allocating a new instance of LocationManager. You can either connect the two controllers between them, like declaring properties and setting them accordingly.
For example, if you instantiate controller B from controller A, you should implement a property for controller B, like firstController, so :
B *controller = [[B alloc] init];
controller.firstController = A;
and then from inside B controller, you control what happens in controller A
An alternate way is to instantiate and control everything from the ApplicationDelegate. It's a more powerful pattern.

Access to variables through delegate

I've go a situatiion in Objective-C where I'm trying to access an object's variable through another object. The classes (simplified):
A.h
#interface A : NSObject {
NSMutableArray *someStuff;
}
#property (nonatomic, retain) NSMutableArray *someStuff;
#end
A.m
#implementation A
#synthesize someStuff;
// blah, blah, blah
Then, because I'm doing an iPhone app, there is an app delegate that contains a variable of this object type:
AppDelegate.h
#interface AppDelegate : NSObject <UIApplicationDelegate> {
A *aPtr;
}
#property (nonatomic, retain) A *aPtr;
#end
AppDelegate.m
#implementation AppDelegate
#synthesize aPtr;
// blah, blah, blah
Then, in another class (in this a view controller), I'm trying to access 'someStuff' in this manner:
AViewController.m
AppDelegate *appDelegate = [[UIApplication sharedApplication] delegate];
NSMutableArray *someArray = appDelegate.aPtr.someStuff;
So, the problem is that this blows up in fine fashion. I think I'm too much of a Java junkie to understand why this won't work. Can anyone elighten me?
Many thanks,
Craig
You need to initialize this in this way
AppDelegate *appDelegate = (AppDelegate*)[[UIApplication sharedApplication] delegate];
NSMutableArray *someArray = appDelegate.someArray;
This will resolve your problem.....
Craig,
appDelegate.aPtr will return null. as it is not initialized yet, and when you try to access some member of a null object,(in java NULLPointerException).Its behavior is as expected.(this blows up in fine fashion).
Thanks,
Ravin is correct. The class definition defines the iVars and properties for a class so you have defined an iVar aPtr that references an object of type A. However, you have not allocated and initialized this object.
An example using the default initialization would be `aPtr = [[A alloc] init]'.
This all sounds suspicious since in ObjC you are allowed to send messages to nil without a problem and properties are just diguised methods. For example you can
view = nil;
view.hidden = NO;
and it doesn't blow up, it just does nothing.
So since appDelegate.aPtr.someStuff is just
[[appDelegate aPtr] someStuff];
and [appDelegate aPtr] does nothing and returns nil so it should be safe to call [[appDelegate aPtr] someStuff] without a problem but also without any results.
So while it is a problem with using objects that hadn't been initialized (which most often should be done in a designated constructor of the appropriate object), since you don't get results that you expect, in my undestanding of "sending message to nil" in ObjC it shouldn't blow up. If it is then either I am missing the point or something other causes the problem and not this call.
EDIT
just checked: if not initialized at all it works as I explained: ObjC allows messages to be sent to nil:
A *aPtr = appDelegate.aPtr;
NSMutableArray *someArray = aPtr.someStuff;
NSLog(#"%#", someArray);
or
NSMutableArray *someArray = appDelegate.aPtr.someStuff;
NSLog(#"%#", someArray);
both don't break and print null.
If you initialize A properly but not initialize someStuff in A it still doesn't break but print null. The problem might be that you initialize aPtr to a different class than A, in which case you get unrecognized selector exception (you should be able to see it in the error log) and program crash.

How to update a variable in one class from another?

I need to set a variable in Class A from Class B. To test this, I have a while loop running in Class A that continuously prints the variable via NSLog. However, no matter what I try, I cannot get Class B to update the variable in Class A in such a way that Class A can read the changes made by Class B. I am pretty sure I have everything hooked up properly in IB. Here's how I have things set up:
//Class A
#interface AppDelegate : NSObject {
NSString *teststring;
}
#property(readwrite,nonatomic,retain) NSString *teststring;
#end
#implementation AppDelegate
#synthesize teststring;
-(id)init{
self = [super init];
if(self) {
teststring = [[NSString alloc] init];
}
return self;
}
-(void)awakeFromNib
{
while(1){
NSLog(#"teststring is %#",teststring);
usleep(500000);
}
}
#end
//Class B
#class AppDelegate;
#interface otherClass : NSObject {
AppDelegate *appdel;
}
-(IBAction)doTest:(id)sender;
#end
#implementation otherClass
-(void)awakeFromNib
{
appdel = [[AppDelegate alloc] init];
}
-(void)doTest:(id)sender
{
appdel.teststring = #"Test";
NSLog(#"Set teststring to %#",appdel.teststring); //this works
}
#end
You are thinking too much about classes (as seemingly some sort of “department” of code) and not enough about objects, and both your wording and your problem demonstrate this.
You have your instance of otherClass creating a second instance of the AppDelegate class. You already had one AppDelegate instance, which is the actual application delegate (because, I assume, you have it in your nib and you have it hooked up to the application's delegate outlet there); now, in -[otherClass awakeFromNib], you are creating another.
You then tell this second AppDelegate instance to set its teststring property to #"Test", and then you ask your second AppDelegate instance for the value of that property, and your second AppDelegate instance dutifully shows you the value you gave it.
The first instance doesn't have the same value for its teststring property because the otherClass object never gave that instance a value for its teststring property. Note that the variables you define in the #interface section are instance variables, which is why different instances of a class can and usually will have different values in those variables. Properties are likewise per-instance, being usually backed by these instance variables.
AppDelegate A (the real application delegate, created in the nib) and AppDelegate B (created by the otherClass object, not anything's delegate) are two separate instances of AppDelegate, with separate teststring variables.
Thus, the solution: Have the otherClass instance talk to the real application delegate, not an AppDelegate instance that it created itself. You could ask the application for its delegate, or (if the otherClass object is in the MainMenu nib) give it an outlet to the application delegate, just like the application has.
However, piling too much stuff into your application delegate class is bad design; each class should have one specific purpose, and generally should fit neatly within one of the Model, View, and Controller classifications. So, assuming your otherClass object should be a controller, move the property into otherClass and make that object the controller of whatever needs the property.