Copying NSDictionary to NSMutable Dictionary doesn't work? - ios

I am trying to copy the contents of one NSDictionary into a NSMutableDictionary.
This is what I have done so far.
#implementation RosterListController
- (void)newMessageReceived:(NSDictionary *)messageContent
{
self.messageDictionary = [[NSMutableDictionary alloc]initWithDictionary:messageContent]; // This is where I am copying
UIApplication *app = [UIApplication sharedApplication];
if (app.applicationState == UIApplicationStateActive)
{
UILocalNotification *localNotif = [[UILocalNotification alloc]init];
if (localNotif)
{
localNotif.alertAction = #"OK";
localNotif.applicationIconBadgeNumber = [[UIApplication sharedApplication] applicationIconBadgeNumber] + 1;
[app presentLocalNotificationNow:localNotif];
}
}
}
Then I handle this notification in appDelegate by showing a AlertView.After that is done..coming back to RosterViewController.
- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex
{
if (buttonIndex == 0) {
NSLog(#"Cancel button presed");
}
else
{
if(chatView) // Chat ViewController
{
[chatView recvdMsg:self.messageDictionary];
}
else
{
UIStoryboard *mainStoryboard = [UIStoryboard storyboardWithName:#"MainStoryboard"
bundle: nil];
chatView=(ChatViewController *)[mainStoryboard instantiateViewControllerWithIdentifier:#"chatviewcontroller"];
NSMutableDictionary *buddy=[[NSMutableDictionary alloc]init];
// The break point stops the app here & shows buddy dictionary as nil.
==> [buddy setObject:[self.messageDictionary objectForKey:#"sender"] forKey:#"jid"];
// Originally it was messageContent dict from the parameter above that I used which worked fine..
//But since I need that dictionary in another method..I copied that dictionary into self.messageDictionary which also gets copied.
// However now the above line causes problems.
// [buddy setObject:[self.messageContent objectForKey:#"sender"] forKey:#"jid"];
chatView.buddyData=buddy;
[self.navigationController pushViewController:chatView animated:YES];
[chatView recvdMsg:self.messageDictionary];
}
}
}

To create NSMutableDictionary from NSDictionary you should use dictionaryWithDictionary which is declared in NSDictionary.h.
NSMutableDictionary *aMutDictFromAnotherDictionary = [NSMutableDictionary dictionaryWithDictionary:YOUR_NSDICTIONARY_OBJECT];

Related

How to initialise a VC or Class iOS, ObjectiveC

When a button is clicked at FirstVC, it will pass data and trigger SecondVC using NSNotificationCenter
During initial launch of the app, because SecondVC has not been initialize yet, so data cannot be passed to SecondVC. NSNotificationCenter cannot function properly. Only after SecondVC has been initialize, NSNotificationCenter will function correctly.
So I need to initialise SecondVC somewhere. Will it be at - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions?
Or how do I programatically call the tab of SecondVC.
FirstVC
#import "Search.h"
#import "Classes.h"
#import "MyTabBarController.h"
#interface Search(){
AppDelegate *appDelegate;
CERangeSlider* _rangeSlider;
NSString *sURL, *strResult, *sRemaining, *sStartTime, *sEndTime, *sSelectedLat, *sSelectedLong;
}
#end
#implementation Search
- (void)viewDidLoad
{
[super viewDidLoad];
}
- (IBAction)btnSearch:(UIButton *)sender {
self.tabBarController.selectedIndex = 1;
sURL = #"Testing 123";
NSDictionary *userInfo = [NSDictionary dictionaryWithObject:sURL forKey:#"theURL"];
[[NSNotificationCenter defaultCenter] postNotificationName:#"toClasses" object:nil userInfo:userInfo];
}
#end
Second VC
- (void)viewDidLoad
{
[super viewDidLoad];
[[NSNotificationCenter defaultCenter]
addObserver:self
selector:#selector(receiveTestNotification:)
name:#"toClasses"
object:nil];
dtDate = [[NSMutableArray alloc] init]; //=== Mutable array to store the dates generated
self.currentPageIndex = 0;
[self setupSegmentButtons];
NSDate *now = [NSDate date];
NSDateFormatter *dateFormatter=[[NSDateFormatter alloc] init];
[dateFormatter setDateFormat:#"dd/MM/YYYY"];
sDtDate = [dateFormatter stringFromDate:now];
[self LoadClasses];
}
-(void)viewWillAppear:(BOOL)animated {
//--- Hide the Top Navigation Controller Bar at the current View
[[self navigationController] setNavigationBarHidden:YES animated:YES];
}
//--- Top Navigation Controller reappear on the next VC
-(void)viewDidDisappear:(BOOL)animated{
[[self navigationController] setNavigationBarHidden:NO animated:YES];
}
-(void) receiveTestNotification:(NSNotification*)notification
{
if ([notification.name isEqualToString:#"toClasses"])
{
NSDictionary* userInfo = notification.userInfo;
NSLog (#"Successfully received userInfo! %#", userInfo);
NSString* sFromSearch = [NSString stringWithFormat: #"%#", userInfo];
NSLog (#"Successfully received test notification! %#", sFromSearch);
}
}
In my opinion, you don't need to use notification or singleton on this case.
Simply, get SecondViewController from self.tabBarController and call the method.
First VC
- (IBAction)btnSearch:(UIButton *)sender {
self.tabBarController.selectedIndex = 1;
sURL = #"Testing 123";
UINavigationController* secondNav = (UINavigationController*)self.tabBarController.viewControllers[1];
SecondViewController* secondViewController = [secondNav.viewControllers firstObject];
[secondViewController handleString:sURL];
}
Second VC
- (void)handleString:(NSString*)string {
// Do whatever you want with string passed from First VC
}
You added observer in viewDidLoad, so it will not work even you create it before user tap on button and send notification. because observer will not be registered. I advise you not use observer to send data in this case. you can save this data elsewhere and use it when seconVC will load. for example in singleton object.
your Singleton object looks like this:
Interface:
#interface DataManager : NSObject
#property (nonatomic, strong) NSDictionary *userInfo;
+ (DataManager *) getInstance;
#end
Implementation:
#implementation DataManager
+ (DataManager *) getInstance {
static DataManager *appManager = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
appManager = [[DataManager alloc] init];
});
return appManager;
}
#end
Now you can access this object where you want and you can assured that only one instance is created.
here is your button click method:
- (IBAction)btnSearch:(UIButton *)sender {
self.tabBarController.selectedIndex = 1;
sURL = #"Testing 123";
NSDictionary *userInfo = [NSDictionary dictionaryWithObject:sURL forKey:#"theURL"];
[DataManager getInstance].userInfo = userInfo;
}
and your viewDidLoad in secondVC
- (void)viewDidLoad {
[super viewDidLoad];
NSDictionary *userInfo = [DataManager getInstance].userInfo;
}

If the application is closed and i receive the push notification, how detect the tap on notification and go to a specific controller?

I have an iOS application in which I am using the push notification to notify the user when the correct answer is posted. If the application is open and if I click on the notification it goes to the specified controller. But if the application is closed and if I receive the notification it does not goes to the specified controller.
-(void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo
{
NSLog(#"User Info %#",userInfo);
NSString* alertValue = [[userInfo valueForKey:#"aps"] valueForKey:#"badge"];
NSLog(#"my message-- %#",alertValue);
int badgeValue= [alertValue intValue];
// NSNumber *identifierString = [[[userInfo valueForKey:#"aps"]valueForKey:#"details"]valueForKey:#"identifire"];
// NSLog(#"identifierString %#",identifierString);
NSString *alertMessage = [[userInfo valueForKey:#"aps"] valueForKey:#"alert"];
NSLog(#"ALertMessage %#",alertMessage);
if ([alertMessage isEqualToString:#"New answer added."]) {
[[UIApplication sharedApplication] setApplicationIconBadgeNumber:badgeValue];
// [[NSUserDefaults standardUserDefaults] setObject:[[[[userInfo valueForKey:#"aps"] valueForKey:#"details"] objectAtIndex:0]valueForKey:#"question"]forKey:#"notificationQuestion"];
// [[NSUserDefaults standardUserDefaults] setObject:[[[[userInfo valueForKey:#"aps"] valueForKey:#"details"] objectAtIndex:0]valueForKey:#"user_image"]forKey:#"notificationImage"];
// NSLog(#"Image %#",[[NSUserDefaults standardUserDefaults]valueForKey:#"notificationQuestion"]);
NSLog(#"User Information %#",userInfo);
NSLog(#"User Details %#",[[userInfo valueForKey:#"aps"] valueForKey:#"details"]);
// NSLog(#"User Details 1%#",[[[userInfo valueForKey:#"aps"] valueForKey:#"details"] objectAtIndex:0]);
// NSLog(#"User Details 1%#",[[[[userInfo valueForKey:#"aps"] valueForKey:#"details"] objectAtIndex:0]valueForKey:#"question"]);
pushDictonary = [[userInfo valueForKey:#"aps"] valueForKey:#"details"];
}
//NSArray *pushDetails = [[userInfo valueForKey:#"aps"] valueForKey:#"details"];
// NSLog(#"Push Details %#",pushDetails);
if (application.applicationState == UIApplicationStateActive ) {
// UILocalNotification *localNotification = [[UILocalNotification alloc] init];
// localNotification.userInfo = userInfo;
// localNotification.soundName = UILocalNotificationDefaultSoundName;
// localNotification.alertBody = [[userInfo valueForKey:#"aps"] valueForKey:#"alert"];
// localNotification.fireDate = [NSDate date];
if ([alertMessage isEqualToString:#"New answer added."])
{
[self createNotificationViewwithUserDictionary:userInfo];
}
}
else if (application.applicationState == UIApplicationStateBackground)
{
NSLog(#"YES");
}
else if (application.applicationState == UIApplicationStateInactive)
{
NSLog(#"YES");
if ([alertMessage isEqualToString:#"New answer added."])
[self pushdetailsViewController];
}
For going to the controller :
-(void)pushdetailsViewController
{
UIStoryboard *mainStoryboard = [UIStoryboard storyboardWithName:#"Main" bundle: nil];
QPYourQuestionController *controller = (QPYourQuestionController*)[mainStoryboard instantiateViewControllerWithIdentifier: #"yourQuestion"];
[[QPCommonClass initializeUserDefaults]setObject:[pushDictonary valueForKey:#"question_id"] forKey:#"currentquestionID"];
NSLog(#"Dictionary %#",pushDictonary);
UINavigationController *navigationController = (UINavigationController *)self.window.rootViewController;
[navigationController pushViewController:controller animated:YES];
}
For the situation when application is closed the remote notification delegate
-(void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo
is not called
In this case the call goes to the following method:
- (BOOL)application:(UIApplication *)application
didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
Hence you can do this to take the user to the VC you want
- (BOOL)application:(UIApplication *)application
didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
// ...
if (launchOptions[UIApplicationLaunchOptionsRemoteNotificationKey]) {
// Do whatever you want
}
}
add this code to your app delegate file
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler {
//you will get notification data in userInfo dict
UIStoryboard * mainStoryboard = [UIStoryboard storyboardWithName:#"Main" bundle: nil];
notificationViewController * notificationVC = [mainStoryboard instantiateViewControllerWithIdentifier: #"notificationViewController"];//set your controller here
[(UINavigationController *)self.window.rootViewController pushViewController:notificationVC animated:YES];
completionHandler(UIBackgroundFetchResultNewData);
}

didFinishLaunchingWithOptions APNS when app is close

I am trying to connect notifications when the app is closed. I need to get a message from APNS and open the desired article by id. The problem is that the message is not read by APNS inside the function didFinishLaunchingWithOptions. I do not know where the mistake. I'm trying to parse (NSDictionary *) launchOptions and pull out the id of the article. Inside the function - didReceiveRemoteNotification everything works fine.
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
[self settingMenuNotification];
[self restKitConfiguration];
[self registerSettingsAndCategories];
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSLog(#"%#",[paths objectAtIndex:0]);
if(launchOptions != NULL) {
NSDictionary *userInfo = [launchOptions valueForKey:UIApplicationLaunchOptionsRemoteNotificationKey];
NSDictionary *apsInfo = [userInfo objectForKey:#"aps"];
[self openNewsDetailNotification:apsInfo];
}
return YES;
}
-(void) openNewsDetailNotification:(NSDictionary*)apsInfo {
if( [apsInfo objectForKey:#"id"] != NULL) { //id - id_article
NSString *id_article = [apsInfo objectForKey:#"id"];
NSNumber *objectId = [NSNumber numberWithInteger: [id_article integerValue]];
NSLog(#"Получил id %#", id_article);
// Загружаем статью
UIWindow *window=[UIApplication sharedApplication].keyWindow;
UIViewController *root = [window rootViewController];
UIStoryboard *storyboard = root.storyboard;
NewsDetailViewController *newsVC = (NewsDetailViewController*)[storyboard instantiateViewControllerWithIdentifier:#"NewsDetailViewController"];
newsVC.objectId = objectId;
UINavigationController *navController = (UINavigationController *)self.window.rootViewController;
[navController.visibleViewController.navigationController pushViewController:newsVC animated:YES];
}
}
Same happened with me.I had added delay in that.Use this code instead of directly calling the function.
[self performSelector:#selector(openNewsDetailNotification:) withObject:apsInfo afterDelay:6.0f];

Handling multiple push notifications got error

I handle push notification when the screen is on by automatically push to a detailViewController. It works fine when there is one or two push notification as I can push each detailViewController on top of each other and pop it back. However, app crash when I have to pop back more than two detailViewControllers. It happens only in iOS 7+.
Set notification Id
- (void)application:(UIApplication *)app didReceiveRemoteNotification:(NSDictionary *)userInfo
{
if(app.applicationIconBadgeNumber!=0)
{
app.applicationIconBadgeNumber = app.applicationIconBadgeNumber - 1;
}
NSString *aps =[NSString stringWithFormat:#"%#",[userInfo objectForKey:#"id"]];
if (app.applicationState == UIApplicationStateActive)
{
NSDictionary *dict = [NSDictionary dictionaryWithObjects:#[[[userInfo objectForKey:#"aps"] objectForKey:#"alert"]] forKeys:#[#"notifyText"]];
[arrNotificationData addObject:dict];
[self showNotificationInActiveMode:[[userInfo objectForKey:#"aps"] objectForKey:#"alert"]];
}
if ([aps isEqualToString:#"1"])
{
[UserDefault setpushnotificationid:[aps intValue]];
}
if ([aps isEqualToString:#"2"])
{
[UserDefault setpushnotificationid:[aps intValue]];
}
if ([aps isEqualToString:#"3"])
{
[UserDefault setpushnotificationid:[aps intValue]];
}
if ([aps isEqualToString:#"4"])
{
[UserDefault setpushnotificationid:[aps intValue]];
}if ([aps isEqualToString:#"5"])
{
[UserDefault setpushnotificationid:[aps intValue]];
}
}
Use singleton class as base class and check for ID and the push and pop the view.
#interface CustomViewController ()
#end
#implementation CustomViewController
- (void)viewDidLoad
{
[super viewDidLoad];
[[NSNotificationCenter defaultCenter]addObserver:self
selector:#selector(appBecomeActive)
name:UIApplicationDidBecomeActiveNotification
object:nil];
}
-(void)appBecomeActive
{
int val=[UserDefault getpushnotificationid];
if(val!=0){
[self checkforpushnotification];
}
}
-(void)checkforpushnotification
{
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:#"MainStoryboard" bundle:nil];
int val=[UserDefault getpushnotificationid];
[UserDefault setpushnotificationid:0];
//.: if current view is profile or setting just dismiss it.because they are present
switch (val)
{
case 1:
{
if( [self checkIfControllerExist:[DealsViewController class]])
{
return;
}else{
detailViewController *VC = (detailViewController *)[storyboard instantiateViewControllerWithIdentifier:#"VCView"];
[self.navigationController pushViewController:VC animated:YES];
}
}
break;
}
}
Now use bace class in your class
#interface detailViewController : CustomViewController

How to edit NSMutableArray in other Class

I have NSMutableArray in "AppDelegate.h"
#property (strong, nonatomic) NSMutableArray *myArray;
and "AppDelegate.m"
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
self.myArray = [[NSMutableArray alloc] init];
return YES;
}
In UITableViewController i add objects in NSMutableArray
- (IBAction)AddComment:(UIBarButtonItem *)sender
{
AppDelegate *appDelegate = (AppDelegate *)[[UIApplication sharedApplication] delegate];
SectionObject *sectionObject = [[SectionObject alloc] init];
sectionObject.id = (NSInteger*)appDelegate.myArray.count;
sectionObject.name = [NSString stringWithFormat:#"New object %i",appDelegate.myArray.count];
[appDelegate.myArray addObject:sectionObject];
[self.tableView reloadData];
}
To edit the object I pass other UITableViewController objects from the array controller
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
UINavigationController *navController = segue.destinationViewController;
ExerciseTableViewController *controller = (ExerciseTableViewController *)navController;
controller.contactdb = [appDelegate.myArray objectAtIndex:[[self.tableView indexPathForSelectedRow] row]];
}
When i am going back to write
-(void)viewWillDisappear:(BOOL)animated {
if ([self.navigationController.viewControllers indexOfObject:self] == NSNotFound) {
self.contactdb.name = self.nameTextField.text;
}
[super viewWillDisappear:animated];
}
I receive an error 'EXC_BAD_ACCESS'. If i not edit self.contactdb.name, I dont have error. How can i edit object in other controller?
Your if-statement:
if ([self.navigationController.viewControllers indexOfObject:self] == NSNotFound)
basically guarantees your view controller has already been removed from the navigation stack. That's why you get a EXC_BAD_ACCESS error when trying to access properties from that view controller. You should place your self.contactdb.name = self.nameTextField.text statement somewhere else.

Resources