0
votes

I have an application where A View Controller (A)is called twice in close succession. Now each time it is called, an NSString object is created, and I need this value to be stored in an NSMutableArray that is a public property of ANOTHER View Controller (B).

In A, I create an instance of the second View Controller (B), and using that instance, add the NSString objects into the NSMutableArray which I've created as a public property. Later, when I am inside View Controller B and print the contents of the NSMutableArray property, the array is empty. Why? Here is the code that is inside View Controller A:

-(void)viewDidLoad {

    ViewControllerA *aVC = [[ViewControllerA alloc] init];
    if (aVC.stringArray == nil) {
        aVC.stringArray = [[NSMutableArray alloc] init];
    }

    [aVC.stringArray addObject:@"hello"];
    [aVC.stringArray addObject:@"world"];

    for (NSString *wow in aVC.stringArray) {
        NSLog(@"The output is: %@", wow);
    }

}

Inside my View Controller B class, I have the following code:

- (IBAction)buttonAction:(UIButton *)sender {


        NSLog(@"Button selected");
        for (NSString *test in self.stringArray) {
            NSLog(@"Here are the contents of the array %@", test);
        }

}

Now the buttonAction method gets called, as I do see the line Button selected in the system output, but nothing else is printed. Why? One thing I want to ensure is that View Controller A is called twice, which means I would like to see in the output, "Hello World", "Hello World" (i.e. printed twice), and not "Hello World" printed just once.

The other thing I wish to point out is that View Controller B may not be called at all, or it may be called at a later point in time. In any case, whenever View Controller B is called, I would like to have the values inside the array available, and waiting for the user to access. How do I do this?

2

2 Answers

1
votes

Your approach is not ideal, potentially leading to a memory cycle, with two objects holding strong pointers to each other.

You can instead achieve your goal in two ways;

Delegate Protocol

This method allows you to set delegates and delegate methods to pass data back and forth between view controllers

in viewControllerA.h

@protocol viewControllerADelegate <NSObject>

- (void)addStringToNSMutableArray:(NSString *)text;

@end

@interface viewControllerA : UIViewController

@property (nonatomic, weak) id <viewControllerADelegate> delegate;

in viewControllerB.m

// create viewControllerA class object
[self.viewControllerA.delegate = self];

- (void)addStringToNSMutableArray:(NSString *)text
{
    [self.mutableArray addObject:text];
}

in viewControllerA.m

[self.delegate addStringToNSMutableArray:@"some text"];

Utility Classes

Alternatively you can use a utility class with publicly accessible methods (and temporary data storage). This allows both viewController classes to access a shared data store, also if you use class methods, you don't even need to instantiate the utility class.

in XYZUtilities.h

#import <Foundation/Foundation.h>

@interface XYZUtilities : NSObject

+ (void)addStringToNSMutableArray;
@property (strong, nonatomic) NSMutableArray *array;

@end

in XYZUtilities.m

+ (void)addStringToNSMutableArray
{
    NSString *result = @"some text";
    [self.array addObject:result];
}

+ (NSArray)getArrayContents
{
    return self.array;
}

in viewControllerA.m

NSString *stringFromObject = [XYZUtilities addStringToNSMutableArray];

in viewControllerB.m

self.mutableArray = [[NSMutableArray alloc] initWithArray:[XYZUtilities getArrayContents]];
0
votes

I'm not sure what kind of a design pattern you are trying to follow but from the looks of it IMHO that's not a very safe one. However, there are many, many ways this could be accomplished.

One thing though, you said that View Controller B may never get allocated and if it is alloc-ed, it will be down the road. So you can't set a value/property on an object that's never been created.

Since you already aren't really following traditional patterns, you could make a static NSMutableArray variable that is declared in the .m of your View Controller B Class and then expose it via class methods.

So it would look like this:

viewControllerB.h

    +(void)addStringToPublicArray:(NSString *)string;

viewContrllerB.m

   static NSMutableArray *publicStrings = nil;

    +(void)addStringToPublicArray:(NSString *)string{

            if (publicStrings == nil){
                publicStrings = [[NSMutableArray alloc]init];
            }

            if (string != nil){
               [publicStrings addObject:string];
            }
    }

Then it would be truly public. All instances of view controller B will have access to it. This, of course is not a traditional or recommended way of doing it—I'm sure that you will have many replies pointing that out ;).

Another idea would be to use a singleton class and store the values in there. Then, when or if view controller B is ever created, you can access them from there.