Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can't call variable from AppDelegate

I have variable in my AppDelegate.m called message, that i would like to use in a view controller, but it's not working. I've tried this solution:

  • If i import the AppDelegate.m into my ViewController.m, i get an error: clang: error: linker command failed with exit code 1 (use -v to see invocation), but if i don't import it i get this: No known class method for selector 'message' at this line: self.toSort = [AppDelegate message];. But when i import ViewController.m into AppDelegate.m i don't get the linker command error, however the other error already exists.

My AppDelegate.h

@property (strong, nonatomic) UIWindow *window;
@property (nonatomic, strong) PNChannel *myChannel;
- (void)getMessage;


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

static NSArray *_message = nil;

@implementation AppDelegate 

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
 //   [self.window makeKeyAndVisible];   
    self.myChannel = [PNChannel channelWithName:currentChannel.username
         shouldObservePresence:YES];

    [self getMessage];

}   
+ (NSArray *)message
{
    if (_message)
        return _message;

    AppDelegate *appDelegate =(AppDelegate *)[[UIApplication sharedApplication] delegate];
    [appDelegate getMessage];

    return nil;
}

- (void)getMessage {

    [PubNub requestFullHistoryForChannel:self.myChannel withCompletionBlock:^(NSArray *contentArray, PNChannel *channel, PNDate *fromDate, PNDate *toDate, PNError *error) {

        _message = contentArray;
        NSLog(@"test log %@", _message);   
    }];
}

ViewController.m

#import "ViewController.h"

//#import "AppDelegate.h"
//#import "AppDelegate.m"

@interface ViewController ()

@end

@implementation ViewController


- (void)viewDidLoad
{
    [super viewDidLoad];

}

- (void)viewWillAppear:(BOOL)animated {

    //AppDelegate *appDelegate = (AppDelegate *)[[UIApplication sharedApplication] delegate];

    //[appDelegate getMessage];

    self.toSort = [AppDelegate message];
    [self getMessageList];

}

I'm sure i did some beginner mistake, but i can't figure it out. The "test log" works, so i think i have to call it in a different way.

Already tried this, but also get an error because message is not a property.

AppDelegate *appDelegate = (AppDelegate *)[[UIApplication sharedApplication] delegate];
NSArray *variableTest = appDelegate.message;
NSLog(@"TEST : %@",variableTest);

UPDATE: I've tried this, but the test log shows null, so something is still wrong.

AppDelegate.h

@property (strong, nonatomic) UIWindow *window;
@property (nonatomic, strong) PNChannel *myChannel;
@property (strong, nonatomic) NSArray *message;
- (void)getMessage;

AppDelegate.m

#import "AppDelegate.h"

@implementation AppDelegate 

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{    
 //   [self.window makeKeyAndVisible];
    self.myChannel = [PNChannel channelWithName:currentChannel.username
         shouldObservePresence:YES];

    [self getMessage];

    }
    return YES;
}

+ (NSArray *)message
{
    if (self.message)
        return self.message;

    AppDelegate *appDelegate =(AppDelegate *)[[UIApplication sharedApplication] delegate];
    [appDelegate getMessage];

    return nil;
}

- (void)getMessage {

    [PubNub requestFullHistoryForChannel:self.myChannel withCompletionBlock:^(NSArray *contentArray, PNChannel *channel, PNDate *fromDate, PNDate *toDate, PNError *error) {

         self.message = contentArray;

         NSLog(@"dev log %@", self.message);
    }];
}

ViewController.m

- (void)viewWillAppear:(BOOL)animated {


    AppDelegate *appDelegate = (AppDelegate *)[[UIApplication sharedApplication] delegate];
    NSArray *variableTest = appDelegate.message;
    NSLog(@"TEST : %@",variableTest);


}

My try based on o Pi's answer:

@interface MessageHistoryData : NSObject {
    NSArray *yourData;
}
@property(nonatomic,retain) NSArray *yourData;
+(MessageHistoryData *)getInstance;

@end

#import "MessageHistoryData.h"

@implementation MessageHistoryData @synthesize yourData;
static MessageHistoryData *instance =nil;
+(MessageHistoryData *)getInstance {
    @synchronized(self) {
        if(instance==nil) {
            instance= [MessageHistoryData new];
        }
    }
    return instance;
}

@end

in my ViewController.m (MessageHistoryData is imported into the .h)

-(void)setupArray {

[PubNub requestHistoryForChannel:my_channel from:nil to:nil limit:100 reverseHistory:NO withCompletionBlock:^(NSArray *contentArray, PNChannel *channel, PNDate *fromDate, PNDate *toDate, PNError *error) {

        MessageHistoryData *data = [MessageHistoryData getInstance];

        data.yourData = contentArray;

        NSLog(@"Dev log2 %@", data.yourData);


}];

}

like image 745
rihe Avatar asked Dec 03 '25 01:12

rihe


2 Answers

I set up a sample project to verify that this works.

In the AppDelegate.h file, publicly declare the message property and -getMessage method:

@interface AppDelegate : UIResponder <UIApplicationDelegate>

@property (strong, nonatomic) UIWindow *window;
@property (readonly, nonatomic) NSString *message;

- (void)getMessage;

@end

In the AppDelegate.m file, implement your methods as you normally would (I explicitly set the property for the sake of example):

#import "AppDelegate.h"

@implementation AppDelegate

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    return YES;
}

- (void)getMessage {
    self.message = @"This is a message";
}

@end

In your ViewController.m file, you should import the AppDelegate header, and you should be free to access the properties:

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

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];

    AppDelegate *delegate = (AppDelegate*)[[UIApplication sharedApplication] delegate];
    NSLog(@"The delegate's message is: %@", delegate.message);  // Logs "The delegate's message is: (null)"
    [delegate getMessage];
    NSLog(@"The delegate's message is: %@", delegate.message);  // Logs "The delegate's message is: This is a message"
}

@end

If the above doesn't work, you should test your PubNub class and ensure it's behavior is predictable.

I don't recommend EVER storing information in your AppDelegate, as that makes the class responsible for doing more than just being your application's delegate with the system. Information like this should be stored in a dedicated store, or made available through a custom PubNub subclass that is accessed as a singleton (if there's no global state to be managed!) or an instance by instance basis.

Let me know if you need any clarification or if the solution above doesn't work for you.

EDIT: Singleton Suggestion

As per my comment, here is one way to handle sharing network data across view controllers

@interface NetworkClient : PubNub

@property (readonly, nonatomic) NSString *message;

/**
 *  Returns a shared network client to be used throughout the app
 */
+ (instancetype)sharedClient;  

- (void)configureWithChannel:(PNChannel*)channel;
- (void)clearChannel;

- (void)getMessagesWithCompletionHandler:(void (^)(NSArray *, PNChannel *, PNDate *, PNDate *, PNError *))

@end

Where sharedInstance uses the technique described here to setup your instance. From there, you can access the client using [NetworkClient sharedClient] and retrieve any data through the instance methods or properties on the client.

I'm also guessing you are new to singletons or iOS in general, so I'm going to recommend you read this article about using singletons, and the blog objc.io to familiarize yourself with some best practices that will absolutely make your life easier.

like image 84
HighFlyingFantasy Avatar answered Dec 05 '25 13:12

HighFlyingFantasy


First there is no need to declare the variable static since [UIApplication sharedAppliction] delegate] will always be the same instance. So just declare a property in the AppDelegate.h file and use that.

in AppDelegat.h

@property(nonatomic, strong) NSArray *message;

in AppDelegate.m use it like this:

self.message

And in your view controller import the .h and do:

AppDelegate *appDelegate =(AppDelegate *)[[UIApplication sharedApplication] delegate];
NSArray *arr = appDelegate.message;
like image 25
Peter Segerblom Avatar answered Dec 05 '25 15:12

Peter Segerblom



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!