PDA

View Full Version : Observation on Reference Object and interclass interaction




mistergreen2011
May 1, 2011, 07:48 PM
Hi,
I'm fairly new so I'm still trying to figure out the nuances of objective C that I might have missed. Correct me if I'm wrong?

I noticed this about referenced objects


//class A
@interface A {
NSArray *myArray;
}
- (void)callMethod;
@end

@implementation
//init sets up a uinavigation
-(void)init {
myArray=[[NSArray alloc] initWithObjects:@"Andy", @"Erik", @"Aaron", nil];
[self.callMethod];
}

-(void)callMethod {
NSlog(@"data %@", myArray);
}
@end

//class B
@interface B {
- (void)callMethodFromA;
}
@end

@implementation
- (void)callMethodFromA {
A *call = [[A alloc] init];
[call callMethod];
[call release];
}
@end



Given this, when 'callMethod' is call from inside class A, it will print "Andy, Eric, Aaron"...

When called from class B, it will print 'null'. This is what I'm seeing on a regular basis. The only way I've been able to resolve this is to create a protocol/delegate so calling from class B won't print out a 'null'

Am I correct in the observation?



chown33
May 1, 2011, 09:03 PM
Your code doesn't compile as given.

EDIT:
After fixing enough bugs to compile and run it, I don't see 'null' being printed:
#import <Foundation/Foundation.h>

//class A
@interface A : NSObject {
NSArray *myArray;
}
- (void)callMethod;
@end

@implementation A
-(id)init {
self = [super init]; // CAUTION: doesn't check for nil here

myArray=[[NSArray alloc] initWithObjects:@"Andy", @"Erik", @"Aaron", nil];
[self callMethod];
return self;
}

-(void)callMethod {
NSLog(@"data %@", myArray);
}
@end

//class B
@interface B : NSObject {
}
- (void)callMethodFromA;
@end

@implementation B
- (void)callMethodFromA {
A *call = [[A alloc] init];
[call callMethod];
[call release];
}
@end


int main(int arcgc, char *argv[])
{
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];

B * myB = [ init];

[myB callMethodFromA];

[myB release];

[pool drain];
return 0;
}
Command-line and output:
[B]gcc -framework Foundation -std=c99 dummy.m
./a.out
2011-05-01 19:10:03.541 a.out[33159:903] data (
Andy,
Erik,
Aaron
)
2011-05-01 19:10:03.544 a.out[33159:903] data (
Andy,
Erik,
Aaron
)

mistergreen2011
May 1, 2011, 09:59 PM
yeah, thanks for taking the time making it work. It was pseudo code not actual code.

hmmm. so I AM missing something.. I'll look into it.

This is an actual code that prints out a null


#import <UIKit/UIKit.h>

@class ReferenceTestViewController;

@interface ReferenceTestAppDelegate : NSObject <UIApplicationDelegate> {
NSArray *myArray;
}

@property (nonatomic, retain) IBOutlet UIWindow *window;

@property (nonatomic, retain) IBOutlet ReferenceTestViewController *viewController;
- (void)output;


@end

#import "ReferenceTestAppDelegate.h"
#import "ReferenceTestViewController.h"

@implementation ReferenceTestAppDelegate


@synthesize window=_window;

@synthesize viewController=_viewController;

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
// Override point for customization after application launch.
myArray=[[NSArray alloc] initWithObjects:@"Andy",@"Erik",@"Aaron",nil];

self.window.rootViewController = self.viewController;
[self.window makeKeyAndVisible];
return YES;
}

- (void)output {
NSLog(@"number %@", myArray);

}

---------------

#import <UIKit/UIKit.h>

@interface ReferenceTestViewController : UIViewController {

}

@end


#import "ReferenceTestViewController.h"
#import "ReferenceTestAppDelegate.h"

@implementation ReferenceTestViewController

- (void)dealloc
{
[super dealloc];
}

- (void)didReceiveMemoryWarning
{
// Releases the view if it doesn't have a superview.
[super didReceiveMemoryWarning];

// Release any cached data, images, etc that aren't in use.
}

#pragma mark - View lifecycle


// Implement viewDidLoad to do additional setup after loading the view, typically from a nib.
- (void)viewDidLoad
{
[super viewDidLoad];
ReferenceTestAppDelegate *nav = [[ReferenceTestAppDelegate alloc] init];
[nav output];
[nav release];


}

chown33
May 2, 2011, 01:36 AM
In your posted code, you have this (let's call it code-fragment A):
ReferenceTestAppDelegate *nav = [[ReferenceTestAppDelegate alloc] init];
[nav output];

In the ReferenceTestAppDelegate class you have this (fragment B):
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
// Override point for customization after application launch.
myArray=[[NSArray alloc] initWithObjects:@"Andy",@"Erik",@"Aaron",nil];
...etc...
}

At what point in fragment A is application:didFinishLaunchingWithOptions: ever called? The answer: never.

If application:didFinishLaunchingWithOptions: isn't called, is myArray ever assigned a value? Answer: no. How could it be otherwise? You only assign a value to myArray in the application:didFinishLaunchingWithOptions: method. No other method ever assigns a value to myArray.

The direct consequence of all this is that myArray is not assigned a value until after application:didFinishLaunchingWithOptions: is called. If that method is never called, then myArray remains nil. Therefore, when you try to NSLog it, it's nil.

If you were to send your instance the application:didFinishLaunchingWithOptions: message before the -output message, then myArray would be assigned a value, and output would show that non-nil value.


The central problem is that you're not performing any of the life-cycle methods of the ReferenceTestAppDelegate instance, yet those methods are the only place where myArray is initialized. You can either call the life-cycle methods directly (only suitable for testing), or you can arrange for them to be called by setting an object as the actual delegate, or you can move the initialization of myArray into a method where it will always be performed.

If you were using an instance of ReferenceTestAppDelegate as an actual app delegate, then the UIKit itself would be calling the life-cycle methods at the proper times. But since you didn't set your directly created instance of ReferenceTestAppDelegate as an actual app delegate, those things aren't happening. These life-cycle methods aren't magic, and they don't happen automatically. If an object isn't the actual app delegate, they won't happen.

If you had used the actual app delegate object, instead of alloc'ing and init'ing a new and separate object, then you should have found that the life-cycle methods are invoked, and when your app has finished launching, then myArray will have a valid value. The actual app delegate is the one returned by [UIApplication sharedInstance].delegate.

Another option would be to define a real -init method in your ReferenceTestAppDelegate class, and assign an array to myArray in that method. Then no matter what happens after that point, life-cycle methods or not, the array will have a valid value.

If that doesn't make sense, then I suggest you study the proper usage of init methods and object creation. The "Allocating and Initializing Objects" section of the Objective-C Programming Language reference covers this:
http://developer.apple.com/library/ios/#documentation/Cocoa/Conceptual/ObjectiveC/Chapters/ocAllocInit.html

I also suggest studying delegates and the delegation pattern, covered in the "Cocoa Design Patterns" section of the Cocoa Fundamentals Guide:
http://developer.apple.com/library/ios/#documentation/Cocoa/Conceptual/CocoaFundamentals/CocoaDesignPatterns/CocoaDesignPatterns.html

Also make sure you understand the difference between a class (such as ReferenceTestAppDelegate), and an instance of that class. You can create multiple instances of a class like ReferenceTestAppDelegate, but only one object can ever be the actual delegate object returned by the delegate property of UIApplication's +sharedInstance method.

Finally, this isn't "interclass interaction" as your thread title indicates. It's inter-object interaction, and there's a big difference. Understanding the difference between a class and an object that's an instance of a class is crucial to understanding all of Objective-C and how it provides object-oriented programming. You would benefit from reading all of the Cocoa Fundamentals Guide, and the early chapters of the Objective-C Programming Language Guide, instead of just the isolated sections I pointed out.

mistergreen2011
May 2, 2011, 12:10 PM
Thanks a bunch for the clarification!