App crashes when trying to load data from a singleton - ios

I have ViewControllerA and ViewControllerB. In each I have this property
#property (retain, nonatomic) NSMutableArray *racersArray;
In ViewControllerA I'm filling the racersArray with custom objects. When I press the burger button on my ViewControllerA, I store my filled _racersArray to singleton array and then I send a notification to ViewControllerB that my _racesArray content is yet in singleton array. I use this method:
- (void)burgerMenu
{
[ArraySingleton sharedManager].sharedArray = _racersArray;
// Send a notification to burger menu view controller to reload it's tableview
[[NSNotificationCenter defaultCenter] postNotificationName:#"ReloadTableViewData" object:nil];
// Opens the burger menu
[self.frostedViewController presentMenuViewController];
}
In ViewControllerB when I receive the notification, I call this method:
- (void)reloadTableviewData
{
_racersArray = [ArraySingleton sharedManager].sharedArray;
[self.tableView reloadData];
}
But after I try to load the data from singleton array to _racersArray, my app crashes with error:
[Racer count]: unrecognized selector sent to instance 0x7fe46aef7330
2016-10-03 23:58:44.091 Stopwatch[67948:6727940] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[Racer count]: unrecognized selector sent to instance 0x7fe46aef7330'
This is how my singleton looks
#synthesize sharedArray;
+ (ArraySingleton *)sharedManager
{
static ArraySingleton *sharedMyManager = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
sharedMyManager = [[ArraySingleton alloc] init];
});
return sharedMyManager;
}
- (id)init
{
if (self = [super init]) {
sharedArray = [[NSMutableArray alloc] initWithObjects:#"picee", nil];
}
return self;
}
Can anyone tell me what am I doing wrong?
Thanks

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;
}

Objective-c calling a method from class method

I am trying to access an instance method from a class method. I am getting this error
+[ActiveVC goToDashBoard]: unrecognized selector sent to class 0x112010
*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '+[ActiveVC goToDashBoard]:
unrecognized selector sent to class 0x112010'
My code
+ (void) removeClosedVisitor:(NSString *) visitorID{
for (NSInteger i = activelist.count - 1; i >= 0 ; i--) {
ActiveItemObject *item = [activelist objectAtIndex:i];
if ([visitorID isEqualToString:item.VisitorId]) {
NSLog(#"Removing Visitor from Active List -- %#", visitorID);
[activelist removeObjectAtIndex:i];
//[self.incommingTable reloadData];
// NSDictionary *activeDictionary = [[NSDictionary alloc] init];
// activeDictionary = [activelist mutableCopy];
//
// [[NSNotificationCenter defaultCenter]
// postNotificationName:#"PassData"
// object:nil
// userInfo:activeDictionary];
[[self class] goToDashBoard];
}
}
}
- (void) goToDashBoard{
NSLog(#"Segue to Dashboard");
UITabBarController *dvc = [self.storyboard instantiateViewControllerWithIdentifier:#"id_tabView"];
[dvc setModalTransitionStyle:UIModalTransitionStyleCoverVertical];
[self presentViewController:dvc animated:YES completion:nil];
}
can some one help me to fix this issue . tnx.
You need to create an instance of your class or convert your class to a singleton. For example: [[ActiveVC sharedInstance] goToDashBoard];
Here's how you create a Singleton Class:
First, create a New file and subclass it from NSObject. Name it anything, we will use CommonClass here. Xcode will now generate CommonClass.h and CommonClass.m files for you.
In your CommonClass.h file:
#import <Foundation/Foundation.h>
#interface CommonClass : NSObject {
}
+ (CommonClass *)sharedObject;
#property NSString *commonString;
#end
In your CommonClass.m File:
#import "CommonClass.h"
#implementation CommonClass
+ (CommonClass *)sharedObject {
static CommonClass *sharedClass = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
sharedClass = [[self alloc] init];
});
return sharedClass;
}
- (id)init {
if (self = [super init]) {
self.commonString = #"this is string";
}
return self;
}
#end
If you want to call instance method then you will need an instance variable so create instance variable of this class and call it.
Make goToDashBoard a class method. Since you are not creating any instance here, if it is not a class method then it can't be executed.
+ (void) goToDashBoard
Do you actually have an instance anywhere? If not you will have to create one:
[self.sharedInstance goToDashBoard]
[[self alloc] init] goToDashBoard]
I assume you do have an instance, because its looks like its a view controller. In which case I suggest you pass the instance into the static method.
+ (void) removeClosedVisitor:(NSString *) visitorID viewController: (xxx) viewController {

Error "'NSInvalidArgumentException', reason: '-[__NSCFDictionary objectAtIndex:]: unrecognized selector sent to instance 0x134d0a3c0'"

I'm implementing Apple Push Notification Services on my app. After getting the notification, I want to get the information and add it into a uitableview. I followed this Pushbots tutorial like this:
In the AppDelegate.m file:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
[Pushbots sharedInstanceWithAppId:#"--my app id--"];
[[Pushbots sharedInstance] receivedPush:launchOptions];
return YES;
}
- (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken {
// This method will be called everytime you open the app
// Register the deviceToken on Pushbots
[[Pushbots sharedInstance] registerOnPushbots:deviceToken];
}
-(void)application:(UIApplication *)application didFailToRegisterForRemoteNotificationsWithError:(NSError *)error{
NSLog(#"Notification Registration Error %#", [error userInfo]);
}
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo {
//Handle notification when the user click it while app is running in background or foreground.
[[Pushbots sharedInstance] receivedPush:userInfo];
NSString *msg = [userInfo valueForKey:#"aps"];
NSLog(#"Push Notification:%#",msg);
[[NSUserDefaults standardUserDefaults]setObject:msg forKey:#"ReceivedNotifications"];
}
In my ViewController.m:
#interface ViewController () <UITableViewDataSource, UITableViewDelegate>
#property (weak, nonatomic) IBOutlet UITableView *notifTableView;
#end
#implementation ViewController
{
NSMutableArray *notif;
}
- (void)viewDidLoad {
[super viewDidLoad];
notif = [[NSUserDefaults standardUserDefaults] objectForKey:#"ReceivedNotifications"];
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return [notif count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"Cell"];
cell.textLabel.text = [notif objectAtIndex:indexPath.row];
return cell;
}
However, I keep getting an error at the console:
[__NSCFDictionary objectAtIndex:]: unrecognized selector sent to instance 0x134d0a3c0
*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[__NSCFDictionary objectAtIndex:]: unrecognized selector sent to instance 0x134d0a3c0'
*** First throw call stack:
(0x180f45900 0x1805b3f80 0x180f4c61c 0x180f495b8 0x180e4d68c 0x100091b28 0x185f8931c 0x185f89484 0x185f787e8 0x185f8dfb0 0x185d2308c 0x185c33778 0x183642b2c 0x18363d738 0x18363d5f8 0x18363cc94 0x18363c9dc 0x1836360cc 0x180efc588 0x180efa32c 0x180e296a0 0x185ca6580 0x185ca0d90 0x100092a1c 0x1809ca8b8)
libc++abi.dylib: terminating with uncaught exception of type NSException
This is my main.m file:
#import <UIKit/UIKit.h>
#import "AppDelegate.h"
int main(int argc, char * argv[]) {
#autoreleasepool {
return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
}
}
What's wrong?
The error message clearly reveals that the receiver of objectAtIndex is an NSDictionary object.
It is created from the aps object of a push notification which is indeed always a dictionary and saved in user defaults with the key ReceivedNotifications.
You have to parse the dictionary to extract the information you want to display.
PS: Do not use valueForKey – which is a KVC method with special behavior –  to get an object from a dictionary. The designated method is objectForKey.
=> Make sure that you really have an array on your hands when you call objectAtIndex:

Encoding and decoding custom objects

I'm having trouble encoding and saving a list of custom objects containing a MKMapItem to NSUserDefaults.
Firstly, I get the selected MKMapItem from an array of MKMapItems used for a tableView and store that in my sharedManager instance. (All the values in sharedManager will be used later to create a custom object).
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
// Get the tapped MKMapItem
MKMapItem *selectedMapItem = self.searchResults[indexPath.row];
// Create a sharedManager instance
MyManager *sharedManager = [MyManager sharedManager];
// Set the workRegion and workLocation in sharedManager
NSLog(#"selectedMapItem: %#", [selectedMapItem name]);
sharedManager.workLocation = selectedMapItem;
// Post a notification to alert the PreviewMapViewController
[[NSNotificationCenter defaultCenter] postNotificationName:#"showAnnotations" object:self.searchResults];
[[NSNotificationCenter defaultCenter] postNotificationName:#"zoomToAnnotation" object:selectedMapItem];
[[NSNotificationCenter defaultCenter] postNotificationName:#"showMap" object:nil];
}
This is the code I use to take the MKMapItem from sharedManager and put it in the custom object I've created:
MyManager *sharedManager = [MyManager sharedManager];
newModel.workLocation = sharedManager.workLocation;
My custom object stores workLocation in its header file with a property as follows:
#property (nonatomic, strong) MKMapItem *workLocation;
This is the implementation file where I encode and decode the workLocation object:
#implementation WorkLocationModel
-(id)init {
// Init self
self = [super init];
if (self)
{
// Setup
}
return self;
}
- (void)encodeWithCoder:(NSCoder *)coder {
[coder encodeObject:self.workLocation forKey:#"workLocation"];
}
-(instancetype)initWithCoder:(NSCoder *)coder {
self = [super init];
if (self)
self.workLocation = [coder decodeObjectForKey:#"workLocation"];
return self;
}
#end
My breakpoint set to catch all the exceptions breaks on the encodeObject line.
The error occurs when I add this custom object to a NSMutableArray and then save that array using:
[[NSUserDefaults standardUserDefaults] setObject:[NSKeyedArchiver archivedDataWithRootObject:_myObjects] forKey:#"myObjects"];
Exception:
-[MKMapItem encodeWithCoder:]: unrecognized selector sent to instance 0x7f9f14acf400
Can anyone help me with this?
UPDATE:
NSData *workLocationData = [NSKeyedArchiver archivedDataWithRootObject:sharedManager.workLocation];
MKMapItem does not conform to NSCoding or SSecureCoding.
You will need to encode the individual items and re-create a MKMapItem on decode.

*** Terminating app due to uncaught exception 'NSInvalidArgumentException',

i am newbie to iOS and i want to implement a splash screen and load the data from database then transmit to another view controller to display data in a UITableView
here is my code
#import "SplashViewController.h"
#import "DataLoader.h"
#import "UISessionTable.h"
#interface SplashViewController ()
#end
#implementation SplashViewController
#synthesize sessionsDataFromDatabase;
-(void) viewDidLoad{
[super viewDidLoad];
double currentTime = [[NSDate date] timeIntervalSince1970];
dispatch_queue_t downloadQueue = dispatch_queue_create("session data loader", NULL);
dispatch_async(downloadQueue, ^{
//code to load session into array
self.sessionsDataFromDatabase = [DataLoader getSessions];
dispatch_async(dispatch_get_main_queue(), ^{
double differance = 5000.0 - ([[NSDate date] timeIntervalSince1970] - currentTime) ;
differance = differance<0? 0:differance;
[[NSTimer scheduledTimerWithTimeInterval: differance target:self
selector: #selector(pushToSessionTableViewController:) userInfo: nil repeats: NO]fire];
});
});
dispatch_release(downloadQueue);
}
-(void) viewDidUnload{
[super viewDidUnload];
self.sessionsDataFromDatabase = nil;
}
-(void) pushToSessionTableViewController{
UISessionTable * obj = [[UISessionTable alloc]init ];
[obj setSessionsData:self.sessionsDataFromDatabase];
[self.navigationController pushViewController:obj animated:YES];
}
#end
i got the following error when run
*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason:
'-[SplashViewController pushToSessionTableViewController:]: unrecognized selector sent
to instance 0x6e45740'
any suggestion ???
The colon at the end is for methods that receive parameters, yours doesn't receive anything. That's why it can't find the method (it assumes it is another undeclared method).
Replace
pushToSessionTableViewController:
with
pushToSessionTableViewController

Resources