i've the following situation.
2 identical react-native apps (differs only for bundleId, app icon etc) structured like this:
-> project structure
My goal it's to emit an event from native side to the JS layer through the bridge when a push notification has been received or tapped by the user (assuming that the app is in foreground and app has finished launching).
On the first App the following code works as expected when i trigger a push notification to my simulator with the command xcrun simctl push <device-id> <bundleId> <filename>.apns, the second app crash immediatly with the following error:
Thread 1: "Error when sending event: pushDelivered with body: <the string passed as body>. RCTCallableJSModules is not set. This is probably because you've explicitly synthesized the RCTCallableJSModules in CustomEventsEmitter, even though it's inherited from RCTEventEmitter."
-> xcode view
Here is the code implementation of RCTEventEmitter's sendEventWithName that provoke the assertion.
I don't know if it's a problem with my implementation. In 1 of the 2 apps works like a charm, in the other 💥.
Anyone can help me find the problem in the code ? Probably a problem with the bridge?
i've tried many times to reinstall pods, clean project and rebuild. The code works on the project A and not on the project B.. i cannot figure out the reason
AppDelegate.h
#import <React/RCTBridgeDelegate.h>
#import <React/RCTBridgeModule.h>
#import <UIKit/UIKit.h>
#import <UserNotifications/UserNotifications.h>
#import <UserNotifications/UNUserNotificationCenter.h>
#interface AppDelegate : UIResponder <UIApplicationDelegate, RCTBridgeDelegate, RCTBridgeModule, UNUserNotificationCenterDelegate>
#property (nonatomic, strong) UIWindow *window;
#property (nonatomic, strong) NSDictionary *receivedNotificationUserInfo;
#end
AppDelegate.mm
#import "AppDelegate.h"
#import <React/RCTBridge.h>
#import <React/RCTBundleURLProvider.h>
#import <React/RCTRootView.h>
#import <React/RCTAppSetupUtils.h>
#import <UserNotifications/UserNotifications.h>
#import "CustomEventsEmitter.h"
#implementation AppDelegate
bool hasFinishedLaunching = false;
CustomEventsEmitter *customEventsEmitter = NULL;
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
hasFinishedLaunching = true;
customEventsEmitter = [CustomEventsEmitter allocWithZone: nil];
RCTAppSetupPrepareApp(application);
RCTBridge *bridge = [[RCTBridge alloc] initWithDelegate:self launchOptions:launchOptions];
NSDictionary *initProps = [self prepareInitialProps];
UIView *rootView = RCTAppSetupDefaultRootView(bridge, #"MyAppName", initProps);
if (#available(iOS 13.0, *)) {
rootView.backgroundColor = [UIColor systemBackgroundColor];
} else {
rootView.backgroundColor = [UIColor whiteColor];
}
self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
UIViewController *rootViewController = [UIViewController new];
rootViewController.view = rootView;
self.window.rootViewController = rootViewController;
[self.window makeKeyAndVisible];
// Define UNUserNotificationCenter
UNUserNotificationCenter *center = [UNUserNotificationCenter currentNotificationCenter];
center.delegate = self;
return YES;
}
- (NSURL *)sourceURLForBridge:(RCTBridge *)bridge
{
#if DEBUG
return [[RCTBundleURLProvider sharedSettings] jsBundleURLForBundleRoot:#"index"];
#else
return [[NSBundle mainBundle] URLForResource:#"main" withExtension:#"jsbundle"];
#endif
}
-(void)applicationDidBecomeActive:(UIApplication *)application
{
application.applicationIconBadgeNumber = 0;
}
// The method will be called on the delegate when the user responded to the notification by opening
// the application, dismissing the notification or choosing a UNNotificationAction. The delegate
// must be set before the application returns from applicationDidFinishLaunching:.
- (void)userNotificationCenter:(UNUserNotificationCenter *)center
didReceiveNotificationResponse:(UNNotificationResponse *)response
withCompletionHandler:(void (^)(void))completionHandler {
NSLog(#"didReceiveNotificationResponse response: %#", response);
NSDictionary *userInfo = response.notification.request.content.userInfo;
if (userInfo[#"_od"]){
// if no listeners has been registered yet, store the value
// this is the case when the notification was clicked from closed app
if(![customEventsEmitter hasListeners]) {
// handle this case ...
}
// if listeners has been registered, emit an event
// this is the case when the notification was clicked from foreground app
else {
[self emitPushTappedEvent:userInfo[#"_od"]];
}
}
if (completionHandler != nil) {
completionHandler();
}
}
//Called when a notification is delivered to a foreground app.
-(void)userNotificationCenter:(UNUserNotificationCenter *)center
willPresentNotification:(UNNotification *)notification
withCompletionHandler:(void (^)(UNNotificationPresentationOptions options))completionHandler
{
NSDictionary *userInfo = notification.request.content.userInfo;
NSLog(#"User Info : %#", userInfo);
[self emitPushDeliveredEvent:userInfo[#"_od"]];
completionHandler(UNNotificationPresentationOptionSound | UNNotificationPresentationOptionAlert | UNNotificationPresentationOptionBadge);
}
-(void)emitPushDeliveredEvent:(NSString*)value {
NSLog(#"emitPushDeliveredEvent called");
[customEventsEmitter sendEventWithName:#"pushDelivered" body:value];
}
-(void)emitPushTappedEvent:(NSString*)value {
NSLog(#"emitPushTappedEvent called");
[customEventsEmitter sendEventWithName:#"pushTapped" body:value];
}
#end
And this are the CustomEventsEmitter files:
CustomEventsEmitter.h
#ifndef CustomEventsEmitter_h
#define CustomEventsEmitter_h
#import <React/RCTBridgeModule.h>
#import <React/RCTEventEmitter.h>
#interface CustomEventsEmitter : RCTEventEmitter <RCTBridgeModule>
- (void)sendEventName:(NSString *)eventName body:(id)body;
- (bool)hasListeners;
#end
#endif
CustomEventsEmitter.m
#import "CustomEventsEmitter.h"
#implementation CustomEventsEmitter
{
bool hasListeners;
}
RCT_EXPORT_MODULE(CustomEventsEmitter);
+ (id)allocWithZone:(NSZone *)zone {
static CustomEventsEmitter *sharedInstance = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
sharedInstance = [super allocWithZone:zone];
});
return sharedInstance;
}
- (NSArray<NSString *> *)supportedEvents {
return #[#"pushDelivered", #"pushTapped"];
}
// Will be called when this module's first listener is added.
-(void)startObserving {
hasListeners = YES;
// Set up any upstream listeners or background tasks as necessary
}
// Will be called when this module's last listener is removed, or on dealloc.
-(void)stopObserving {
hasListeners = NO;
// Remove upstream listeners, stop unnecessary background tasks
}
-(bool)hasListeners {
return hasListeners;
}
- (void)sendEventName:(NSString *)eventName body:(id)body {
if (hasListeners) {
NSLog(#"CustomEventsEmitter sendEventName emitting event: %#", eventName);
[self sendEventWithName:eventName body:body];
} else {
NSLog(#"CustomEventsEmitter sendEventName called without listeners: %#", eventName);
}
}
#end
HELP ME UNDERSTAND PLEASEEEE
Oh i've solved it!
It was a mistake of mine.
The AppModule didn't invoke the CustomEventsEmitter's methods correctly..
changing the code like below makes the events be emitted correctly through the RN bridge
-(void)emitPushDeliveredEvent:(NSString*)value {
NSLog(#"emitPushDeliveredEvent called");
[customEventsEmitter sendEventName:#"pushDelivered" body:value];
//[customEventsEmitter sendEventWithName:#"pushDelivered" body:value];
}
-(void)emitPushTappedEvent:(NSString*)value {
NSLog(#"emitPushTappedEvent called");
[customEventsEmitter sendEventName:#"pushTapped" body:value];
//[customEventsEmitter sendEventWithName:#"pushTapped" body:value];
}
I'm working on a brownfield integration on react-native-asyncstorage.
In the pod file, RNCAsyncStorage.h has the following:
#import <React/RCTBridgeModule.h>
#import <React/RCTInvalidating.h>
#import "RNCAsyncStorageDelegate.h"
...
#interface RNCAsyncStorage : NSObject <RCTBridgeModule,RCTInvalidating>
...
- (void)multiGet:(NSArray<NSString *> *)keys callback:(RCTResponseSenderBlock)callback;
And in my AppDelegate.m I have
#implementation AppDelegate {
__weak RCTBridge *_bridge;
}
...
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
...
RCTBridge *bridge = [[RCTBridge alloc] initWithDelegate:self launchOptions:launchOptions];
...
}
And in my Stuff.m I have this in my method:
#import <RNCAsyncStorage/RNCAsyncStorage.h>
....
RNCAsyncStorage *asyncStorage = [self.bridge moduleForClass:[RNCAsyncStorage class]];
[asyncStorage multiGet:#[#"playerQueue"]] callback:^(NSArray *response){
NSObject *count = response[0];
if ([count isKindOfClass:[NSError class]]) {
// Failed to get count
return;
}
// Use count here
}];
But I kept getting the error saying No visible #interface for 'RNCAsyncStorage' declares the selector 'multiGet:'.
There's a multiGet selector being declared in the header file as well as in the .m file.
I should say that RNCAsyncStorage is imported from Pods, but I did try to pull those into my project and still getting the same error. Anything I should do to address this? Thanks!
Just a mistake in syntax. There is an extra ], the correct call is:
[asyncStorage multiGet:#[#"playerQueue"] callback:^(NSArray *response){
NSObject *count = response[0];
if ([count isKindOfClass:[NSError class]]) {
// Failed to get count
return;
}
// Use count here
}];
I followed OneSignal's set up guide, added an extension all named properly and have this file that they provided:
#import <OneSignal/OneSignal.h>
#import "NotificationService.h"
#interface NotificationService ()
#property (nonatomic, strong) void (^contentHandler)(UNNotificationContent *contentToDeliver);
#property (nonatomic, strong) UNNotificationRequest *receivedRequest;
#property (nonatomic, strong) UNMutableNotificationContent *bestAttemptContent;
#end
#implementation NotificationService
- (void)didReceiveNotificationRequest:(UNNotificationRequest *)request withContentHandler:(void (^)(UNNotificationContent * _Nonnull))contentHandler {
self.receivedRequest = request;
self.contentHandler = contentHandler;
self.bestAttemptContent = [request.content mutableCopy];
[OneSignal didReceiveNotificationExtensionRequest:self.receivedRequest withMutableNotificationContent:self.bestAttemptContent];
self.contentHandler(self.bestAttemptContent);
}
- (void)serviceExtensionTimeWillExpire {
// Called just before the extension will be terminated by the system.
// Use this as an opportunity to deliver your "best attempt" at modified content, otherwise the original push payload will be used.
[OneSignal serviceExtensionTimeWillExpireRequest:self.receivedRequest withMutableNotificationContent:self.bestAttemptContent];
self.contentHandler(self.bestAttemptContent);
}
#end
Also copied all their code for AppDelegate as outlined in their setup guide here:
https://documentation.onesignal.com/docs/ios-sdk-setup plus some other code to create the 'center' variable as someone recommended on github. Adding this instance in AppDelegate did make it so that 'didReceiveRemoteNotification' gets called, but not didReceiveNotificationExtensionRequest.
#import "AppDelegate.h"
#interface AppDelegate ()
#define SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(v) ([[[UIDevice currentDevice] systemVersion] compare:v options:NSNumericSearch] != NSOrderedAscending)
#define SYSTEM_VERSION_LESS_THAN(v) ([[[UIDevice currentDevice] systemVersion] compare:v options:NSNumericSearch] == NSOrderedAscending)
#end
#import <OneSignal/OneSignal.h>
#implementation AppDelegate
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
// Replace '11111111-2222-3333-4444-0123456789ab' with your OneSignal App ID.
[OneSignal initWithLaunchOptions:launchOptions
appId:#"xxxxxxx (my app id is here)"
handleNotificationAction:nil
settings:#{kOSSettingsKeyAutoPrompt: #false}];
OneSignal.inFocusDisplayType = OSNotificationDisplayTypeNotification;
// Recommend moving the below line to prompt for push after informing the user about
// how your app will use them.
[OneSignal promptForPushNotificationsWithUserResponse:^(BOOL accepted) {
NSLog(#"User accepted notifications: %d", accepted);
}];
UNUserNotificationCenter *center = [UNUserNotificationCenter currentNotificationCenter];
center.delegate = self;
// Call syncHashedEmail anywhere in your iOS app if you have the user's email.
// This improves the effectiveness of OneSignal's "best-time" notification scheduling feature.
// [OneSignal syncHashedEmail:userEmail];
return YES;
}
-(void) application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void
(^)(UIBackgroundFetchResult))completionHandler
{
// iOS 10 will handle notifications through other methods
if( SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO( #"10.0" ) )
{
NSLog( #"iOS version >= 10. Let NotificationCenter handle this one." );
// set a member variable to tell the new delegate that this is background
//this block here gets called when I debug
return;
}
NSLog( #"HANDLE PUSH, didReceiveRemoteNotification: %#", userInfo );
// custom code to handle notification content
if( [UIApplication sharedApplication].applicationState == UIApplicationStateInactive )
{
NSLog( #"INACTIVE" );
completionHandler( UIBackgroundFetchResultNewData );
}
else if( [UIApplication sharedApplication].applicationState == UIApplicationStateBackground )
{
NSLog( #"BACKGROUND" );
completionHandler( UIBackgroundFetchResultNewData );
}
else
{
NSLog( #"FOREGROUND" );
completionHandler( UIBackgroundFetchResultNewData );
}
}
#end
I need 'didReceiveNotificationExtensionRequest' since I'm trying to use iOS 10's mutable content feature. I've put in breakpoints and am sure that didReceiveNotificationExtensionRequest is never called, I'm wondering if I need to hook up the class somewhere else because the .m file never does anything. Any help appreciated
If it matters my phone is running ios 10.0 (so should support the mutable content) and OneSignal version is (2.5.4)
Thanks
On iOS 10 didReceiveRemoteNotification method will not be called...you should go for
- (void)userNotificationCenter:(UNUserNotificationCenter *)center
willPresentNotification:(UNNotification *)notification
withCompletionHandler:(void (^)(UNNotificationPresentationOptions))completionHandler
I am a beginner in developing IOS app. Now i want to send a refreshToken data from a method in AppDelegate to mainViewController.
i can't get it first time when download it. But second time i can get it.
i think it takes some time when it creation first time and it is stored after.
Please help me, how to send data in a method from AppDelegate to ViewController. ultimately, i want to store it to database and send push notification message to user from serverside.
i use following code.
//AppDelegate.h
#class ViewController;
#import <UIKit/UIKit.h>
#import "ViewController.h"
#interface AppDelegate : UIResponder <UIApplicationDelegate>
#property (weak, nonatomic) ViewController *myViewController;
#property (strong, nonatomic) UIWindow *window;
#property (weak, nonatomic) IBOutlet UIWebView *webView;
#end
//AppDelegate.m
- (void)tokenRefreshCallback: (NSNotification *)notification {
NSString *refreshToken = [[FIRInstanceID instanceID] token];
NSLog(#"InstanceID token: %#", refreshToken);
//
if(refreshToken){
[[NSUserDefaults standardUserDefaults] setObject:refreshToken forKey:#"token"];
[[NSUserDefaults standardUserDefaults] synchronize];
}
// Connect to FCM since connection may have failed when attempted before having a token.
[self connectToFirebase];
}
//ViewController.h
#import <UIKit/UIKit.h>
#import "AppDelegate.h"
#interface ViewController : UIViewController
#end
//ViewController.m
- (void)viewDidLoad {
[super viewDidLoad];
AppDelegate *appDelegate = [[UIApplication sharedApplication] delegate];
appDelegate.myViewController = self;
//get tokenId
NSString *token = [[NSUserDefaults standardUserDefaults] objectForKey:#"token"];
if(token){
NSLog(#"i have token~!!!: %# ", token);
}else NSLog(#"no token!: %# ", token);
// Do any additional setup after loading the view, typically from a nib.
}
Thanks all.
use NSNotifiactionCenter
in your Appdelegate when token is available post a notification with the token(add following code in app delegate where token is available)
NSDictionary* userInfo = #{#"token": #"YOUR_TOKEN"};
[[NSNotificationCenter defaultCenter] postNotificationName:#"refreshTokenAvailale" object:self userInfo:userInfo];
And put this code in your main view controller
- (void) dealloc
{
// If you don't remove yourself as an observer, the Notification Center
// will continue to try and send notification objects to the deallocated
// object.
[[NSNotificationCenter defaultCenter] removeObserver:self];
}
- (id) init
{
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(receiveNotification:)
name:#"refreshTokenAvailale"
object:nil];
return self;
}
- (void) receiveNotification:(NSNotification *) notification
{
if ([notification.name isEqualToString:#"refreshTokenAvailale"])
{
NSDictionary* userInfo = notification.userInfo;
NSString* token = userInfo[#"token"];
}
}
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);
}];
}
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.
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;
You have to put public variables into your header file.
Your getMessage method uses an async call to get the messages. If you can't retrieve it in a sync way maybe you should call getMessage as soon as possible.
Better yet you could also use blocks to return the messages async:
+ (void)asyncMessage:(void(^)(NSArray * message))callbackBlock
{
if (_message)
{
callbackBlock(_message);
return;
}
[PubNub requestFullHistoryForChannel:self.myChannel withCompletionBlock:^(NSArray *contentArray, PNChannel *channel, PNDate *fromDate, PNDate *toDate, PNError *error) {
_message = contentArray;
callbackBlock(_message);
NSLog(#"test log %#", _message);
}];
}
never import .m class in xcode because this throws cling: error.
if u want to NSArray defined in appdelegate to use later in your any view controller,there may be many approaches.some of them are-
initilise your array in appdelegate.h like this
#property(nonatmoic,retain)nsarray *message;
then in your appdelegate.m class in didfinishlaunchingwithOptions method allocate memory to this array-
message=[[nsarray alloc]initwithobjects:#"abc"];
then in your view controller make object of app delegate and access this property like this-
NSLog(#"array is %#",appdelegateobject.message);
In your first question you trying to return this array by class method,but in appdelegate you returning nil,so how will u get this message array,
Take the message variable and paste it into the .h then delete it from the .m
You can not import a implement file in your implement file like this.
AppDelegate.m
#import "AppDelegate.h"
#import "ViewController.m" // This is the reason causes error.
I made this errors before....
Modify like this easily fix this problem.
AppDelegate.m
#import "AppDelegate.h"
#import "ViewController.h"
you need to properties the message array to make public
AppDelegate.h
#property (strong, nonatomic) NSArray *message;
Hope it helps you..