0

Is it possible to create an instance of an object in class A and access that same instance of the object from class B? I am trying to develop an app that creates a TCP Socket using NSInputStream and NSOutputStream and need more than one class to be able to access it.

Thank you, Travis Elliott

edit

Here is the code I am working with. Its a program that deals with socket connections. I basically need to be able to communicate to the same socket from my appDelegate and View controller. Here is the code I have based on your help. I am using the appDelegate as the control(D in your example), perhaps I cannot do this. CommunicationHub is the class I need to control the same instance of from both AppDelegate and ViewController.

AppDelegate.h

#import <UIKit/UIKit.h>
#import "ViewController.h"
#import "CommunicationHub.h"

@interface AppDelegate : UIResponder <UIApplicationDelegate>{

ViewController *viewController;
CommunicationHub *cHub;
}

@property (strong, nonatomic) UIWindow *window;
@property (strong, retain) ViewController *viewController;
@property (strong, retain) CommunicationHub *cHub;

-(void)CreateInstances;


@end

AppDelegate.m

#import "AppDelegate.h"
#import "ViewController.h"

@implementation AppDelegate
@synthesize viewController;
@synthesize cHub;

@synthesize window = _window;

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
    [self CreateInstances];
    // Override point for customization after application launch.
    return YES;
}

-(void)CreateInstances{
    NSLog(@"Inside CreateInstances");
    CommunicationHub *cHub = [[CommunicationHub alloc] init];
    viewController = [[ViewController alloc] init];
    [viewController initWithcHub:cHub];
    NSLog(@"ID of cHub in AppDelegate is %i", cHub);


}

- (void)applicationWillResignActive:(UIApplication *)application
{
    NSLog(@"Application Will Resign Active");
    [cHub disconnect];
}

@end

ViewController.h

#import <UIKit/UIKit.h> 
#import "CommunicationHub.h"

@interface ViewController : UIViewController 
{
    CommunicationHub *cHub;
}

@property (strong, nonatomic) IBOutlet UITextField *IPAddress;
@property (strong, nonatomic) IBOutlet UITextField *PortNumber;
- (IBAction)goAwayKeyBoard:(id)sender;
- (IBAction)touchBackground:(id)sender;
-(void) initWithcHub:(CommunicationHub *)ptr;
- (IBAction)connectSocket:(id)sender;
- (IBAction)disconnectSocket:(id)sender;

@end

ViewController.m

#import "ViewController.h"

@interface ViewController ()

@end

@implementation ViewController
@synthesize IPAddress;
@synthesize PortNumber;

-(void) initWithcHub:(CommunicationHub *)ptr
{
    cHub = [[ptr retain]init];
    NSLog(@"id of cHub in ViewController is %i", cHub);
}

- (IBAction)connectSocket:(id)sender 
{
    //Called by button on UI.
    int portNumber = [PortNumber.text intValue];

    [cHub Connect:(int *)portNumber ipAddress:(IPAddress.text)];
}

- (IBAction)disconnectSocket:(id)sender 
{
    //Called by button on UI.
    [cHub disconnect];
}


- (void)viewDidLoad
{
    [super viewDidLoad];
    // Do any additional setup after loading the view, typically from a nib.
}

- (void)viewDidUnload
{
    [self setIPAddress:nil];
    [self setPortNumber:nil];
    [super viewDidUnload];
    // Release any retained subviews of the main view.
}

- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
    if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPhone) {
        return (interfaceOrientation != UIInterfaceOrientationPortraitUpsideDown);
    } else {
        return YES;
    }
}

-(IBAction)goAwayKeyBoard:(id)sender{

    [self resignFirstResponder];
}

- (IBAction)touchBackground:(id)sender {
    [IPAddress resignFirstResponder];
    [PortNumber resignFirstResponder];
}


@end

CommunicationHub.h

#import <UIKit/UIKit.h>

NSInputStream *inputStream;
NSOutputStream *outputStream;

@interface CommunicationHub : NSObject <NSStreamDelegate>

- (void)Connect:(int *)port ipAddress:(NSString *)ipAddress;
- (void) disconnect;

@end

CommunicationHub.m

#import "CommunicationHub.h"

@implementation CommunicationHub

- (void)Connect:(int *)port ipAddress:(NSString *)ipAddress 
{
    NSLog(@"inside connect method");

    if ([inputStream streamStatus] == 0 ||[inputStream streamStatus] ==  5 ||[inputStream streamStatus] == 6 ||[inputStream streamStatus] == 7) 
    {
        NSString *myString = ipAddress;
        CFStringRef *myCFString = (__bridge CFStringRef)myString;
        CFReadStreamRef readStream;
        CFWriteStreamRef writeStream;
        CFStreamCreatePairWithSocketToHost(NULL, myCFString, port, &readStream, &writeStream);
        inputStream = (__bridge NSInputStream *)readStream;
        outputStream = (__bridge NSOutputStream *)writeStream;
        [inputStream setDelegate:self];
        [outputStream setDelegate:self];

        [inputStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
        [outputStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
        [inputStream open];
        [outputStream open];
    }
}

- (void) disconnect
{
    NSLog(@"inside disconnect method");

    if (inputStream != nil) {
        if ([inputStream streamStatus] == 2) {
            NSLog(@"Disconnecting Streams");
            [inputStream close];
            [outputStream close];
        }else {
            NSLog(@"Stream is not Open");
            int status = [inputStream streamStatus];
            NSLog(@"Stream Status is %i", status);
        }

    }else {
        NSLog(@"Input Stream equals Nil");
    }

}

@end
Travis Elliott
  • 291
  • 2
  • 5
  • 18
  • To make it short: Pass a pointer of the instance to the class that needs to use it. – ATaylor Jul 26 '12 at 20:21
  • Okay, where do I start...first off: Remove that int * cast from 'Connect'. It's not just unnecessary, but also potentially dangerous, if you don't use it as 'int' parameter, but as actual pointer. Next: Do not use the same names for local variables and instance variables, since local naturally hides instance variables, possibly leading to leaks. Next: [[ViewController alloc] initWithCHub] -> One method call. Not init and then 'init' again. (Or revise your method names). However, all design flaws aside...what exactly is the current problem? – ATaylor Jul 31 '12 at 20:09
  • Ill get those corrected. My main problem is when the app boots up my appDelegate calls CreateInstances locally which creates an instance of the CommunicationHub class and ViewController class then it calls the method initWithcHub on ViewController which i guess is suppose to create an object to CommunicationHub called cHub. This works and I can print the ids of the cHub object at the app delegate and view controller but when I press a button on the UI to call the connect method on cHub the cHub object is nil. It seems that when I call the initWithcHub its a new instance. – Travis Elliott Jul 31 '12 at 20:50
  • No, it's NOT supposed to 'create an object', but 'pass a reference to the already created object'. Remove the 'init' after the retain, and tell me if it works better, please. – ATaylor Aug 01 '12 at 06:01
  • I actually did try removing the init since it seemed like that would not be correct but that did not seem to work either. Currently the code I have is cHub = [ptr retain]; I believe the problem is when I call this line in the initWithcHub:(CommunicationHub *)ptr method a new instance of viewController is created by the appDelegate so the cHub object is created by that instance but is only available in that particular instance so if I press a button to call a method in viewController that cHub object is nil. Is that possible? – Travis Elliott Aug 01 '12 at 14:49
  • No, actually, assuming this IS the code you're working with, this is impossible. viewController gets instantiated by [[ViewController alloc] init]; After that, the reference is passed. Have you checked, that cHub is NOT nil, after you created the object? (Before passing the pointer on?) – ATaylor Aug 01 '12 at 15:01

1 Answers1

0

To make it long: Assuming you have class A, B and C.

C needs to be accessible, from both A and B. Now, let's assume we have controller D, which instantiates both A and B. Have D instantiate C first, and store it in a variable.

C *C_Class = [[[C alloc] init] autorelease];

Next, instantiate A and B with C (I'm assuming 'retain properties' here)

self.A_Class = [[[A alloc] initWithC:C_Class] autorelease];
self.B_Class = [[[B alloc] initWithC:C_Class] autorelease];

In both classes, you need the instance method:

- (id)initWithC:(C *)C_Class;

and in the .m file:

- (id)initWithC:(C *)C_Class {
    C_C = [C_Class retain]; //Assuming a regular instance variable
}

- (void) dealloc {
    [C_C release];  //All that is retained, must be released.
}

From this moment on, you have access to that one instance of Class C in classes A and B, via the name 'C_C'.

Now, please mind that this is just written from the back of my head and prone to have errors, but it SHOULD be alright.

I hope it helps :)

Edit: Since the OP seems to have trouble with these code fragments, I'll add a more complete code.

Let's start with the control class 'D'.

D.h:

#import "A.h"
#import "B.h"

@interface D : NSObject

-(void)CreateInstances;

@property (strong, retain) A *A_Class;
@property (strong, retain) B *B_Class;

@end

D.m:

#import "D.h"
#import "C.h"

@implementation D

-(void)CreateInstances {
    C *C_Class = [[C alloc] init] autorelease];
    self.A_Class = [[[A alloc] initWithC:C_Class] autorelease];
    self.B_Class = [[[B alloc] initWithC:C_Class] autorelease];
}

@end

A.h (B.h mirrors this behavior, maybe consider using a superclass for both)

#import "C.h"

@interface A : NSObject {
    C *C_Class;           //Class Reference to the C-Object
}

-(id) initWithC:(C *)ptr; //Initialization method, which takes a 'C'-Object.

@end;

A.m

#import "A.h"

@implementation A

- (id) initWithC:(C *)ptr {
    C_Class = [ptr retain]; //So the object doesn't get released prematurely.
}

- (void) dealloc {
    [C_Class release];      //To avoid memory leaks.
}

@end

Now, please remember, that I wrote this off the top of my head and didn't run it through a compiler, but it SHOULD work, save typos and the likes.

Another edit: After the OP added his own code, I will post relevant bits of 'corrected' code here.

AppDelegate.m

-(void)CreateInstances{
    NSLog(@"Inside CreateInstances");
    cHub = [[CommunicationHub alloc] init]; //We're using the instance variable. Not the local one.
    viewController = [[ViewController alloc] initWithcHub:cHub];
    //[viewController initWithcHub:cHub];  //You may want to rethink your function names.
    NSLog(@"ID of cHub in AppDelegate is %i", cHub);
}

ViewController.m

//If a method names STARTS with 'init', it SHOULD initialize the object.
-(id) initWithcHub:(CommunicationHub *)ptr
{
    self = [super init];     //Calls the 'init' from the parent class.
    if(self) {
        cHub = [ptr retain]; //Just retain. After all, the object IS initialized already.
        NSLog(@"id of cHub in ViewController is %i", cHub);
    }
    return self;
}

- (void) dealloc {
    [cHub release]; //Basic rule of memory management: ALL that is retained, must be released. In dealloc, at latest.
}

- (IBAction)connectSocket:(id)sender 
{
    //Called by button on UI.
    //Do not pass a pointer to anything, unless you mean to use a pointer.
    [cHub Connect:[PortNumber.text intValue] ipAddress:(IPAddress.text)];
}

The rest should be somewhat correct, or at least not subject of this question.

ATaylor
  • 2,598
  • 2
  • 17
  • 25
  • Wow, talk about alot to take in. I will try this out and let you know how it goes. – Travis Elliott Jul 26 '12 at 20:56
  • So the method that you create in the A an B classes initWithC, the C class needs to pass this method self? I am able to call this method by passing it self from C class and I print the ids and they match but I am not able to call any methods of my C class from the A or B class. – Travis Elliott Jul 27 '12 at 16:27
  • No, it seems you got me wrong. There's a fourth class in this little mix. The 'main controller' (D in my example), so to speak. This main controller creates instances of A, B and C (has references to all three). Also, be sure to import C.h in the header files to A and B and make the pointer to the class itself, instead of 'id'. I may be able to help you better, if you post the code you have in your question. Comments aren't really suited for this. – ATaylor Jul 28 '12 at 05:34
  • This call creates new instance of A or B class so calling the C object is nil: self.A_Class = [[[A alloc] initWithC:C_Class] autorelease]; Seems to be the smoking gun here. – Travis Elliott Jul 31 '12 at 18:32