Why only BOOL property of AppDelegate is throwing EXC_BAD_ACCESS? - ios

In appdelegate.h
#property (nonatomic,assign) bool isPhone;
In appdelegate.m
if ( IDIOM == IPAD ) {
self.isPhone = NO;
objDrawing = [[DEDrawingPage alloc]initWithNibName:#"DEDrawingPageiPad" bundle:nil];
} else {
self.isPhone = YES;
objDrawing = [[DEDrawingPage alloc]initWithNibName:#"DEDrawingPageiPhone" bundle:nil];
}
+(DEAppDelegate *)getDelegate
{
return (DEAppDelegate *)[[UIApplication sharedApplication] delegate];
}
In viewController.m
if([DEAppDelegate getDelegate].isPhone) // bad access here
{
objSettingPage = [[DESettings alloc]initWithNibName:#"DESettingsiPhone" bundle:nil];
}
Accessing isPhone property is giving bad access in IF condition. This is happening with BOOL type property only. I have tried taking NSNumber or NSString. They are working fine. Why BOOL is giving bad access. I have also tried with (lowercase) bool, that too is useless.

Can you clean the build and re-check the issue. I have followed the above same steps, didn't get issue.
Also, have you defined below in delegate.h
+(DEAppDelegate *)getDelegate;

Why don't use macro of appDelegate object which is given below to use in all your application define in your project's .pch file :
#define appDelegateObject ((AppDelegate *)[UIApplication sharedApplication].delegate)
Note : change AppDelegate to your Application Delegate instance
Use this macro like this :
if(appDelegateObject.isPhone) //Here isPhone is property of appDelegate
{
//anything here
}

Related

category property for AppDelegate not working

I've extended AppDelegate with my category. The goal is initiate server request and show notification, when user entering some geofence with terminated app. This all done in class GeoNotificationManager. All I need to do - instantiate this class once app launched from location event.
Everything works, except the PROBLEM: - when #property (strong) GeoNotificationManager* geof; is inside category, code inside GeoNotificationManager doesn't work (no server requests, no notifications). And when it's inside AppDelegate itself, everything works as expected.
Also I tried without having property in catergory, it doesn`t work too.
GeoNotificationManager* manager = [GeoNotificationManager new];
[manager sendTestServerRequest:#"test"]; // REQUEST NOT SENDING, WHY???
//AppDelegate+Geofence.h
#import "AppDelegate.h"
#class GeoNotificationManager;
#interface AppDelegate (Geofence)
#property (strong) GeoNotificationManager* geof;
#end
NSString * const kNewPropertyKey = #"kNewPropertyKey";
#class GeoNotificationManager;
#implementation AppDelegate(Geofence)
-(BOOL)application:(UIApplication *)application willFinishLaunchingWithOptions:
(NSDictionary<UIApplicationLaunchOptionsKey,id> *)launchOptions {
if ([launchOptions objectForKey:UIApplicationLaunchOptionsLocationKey])
{
self.geof = [GeoNotificationManager new];
[self.geof sendTestServerRequest:#"test"];
}
return true;
}
// I don't understand what is that below, but seems it's required for having property in category
- (void)setGeof:(id)aObject
{
objc_setAssociatedObject(self, (__bridge const void * _Nonnull)(kNewPropertyKey),
aObject, OBJC_ASSOCIATION_ASSIGN);
}
- (id)geof
{
return objc_getAssociatedObject(self, (__bridge const void * _Nonnull)(kNewPropertyKey));
}
#objc class GeoNotificationManager : NSObject, CLLocationManagerDelegate {
let locationManager = CLLocationManager()
override init() {
super.init()
locationManager.delegate = self
locationManager.desiredAccuracy = kCLLocationAccuracyBest
locationManager.allowsBackgroundLocationUpdates = true
locationManager.showsBackgroundLocationIndicator = true
}
// OTHER CODE, -didEnterRegion, server request etc
OBJC_ASSOCIATION_ASSIGN just should be replaced with OBJC_ASSOCIATION_RETAIN, and it works!
But if anyone knows how to do this with local variable, please share

How to create referencing variables?

I'm making an app for practice. This app shares with a simple model through AppDelegate. To manipulate the model, I got an NSDictionary object from the model and allocate it to a viewController property. but It seems too verbose.
// viewController.h
#property (nonatomic, strong) NSMutableDictionary *bookDetail;
#property (nonatomic, strong) bookModel *modelBook;
// viewController.m
- (void)setLabel {
self.label_name.text = self.bookDetail[#"name"];
self.label_author.text = self.bookDetail[#"author"];
}
- (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
id appDelegate = [[UIApplication sharedApplication] delegate];
self.modelBook = [appDelegate modelBook];
self.bookDetail = self.modelBook.bookList[self.modelBook.selectedId];
[self setLabel];
self.editMod = NO;
}
- (IBAction)editSave:(id)sender {
if (self.editMod == NO) {
....
[self.nameField setText:self.bookDetail[#"name"]];
[self.authorField setText:self.bookDetail[#"author"]];
....
} else {
self.bookDetail = [#{#"name" : self.nameField.text,
#"author" : self.authorField.text} mutableCopy];
[self setLabel];
....
}
}
#end
*bookDetail work like a copy of self.modelBook.bookList[self.modelBook.selectedId] not a reference. Using self.modelBook.bookList[self.modelBook.selectedId] works well, but I don't want to. How Can I simplify this code?
*bookDetail work like a copy of self.modelBook.bookList[self.modelBook.selectedId] not a reference. Using self.modelBook.bookList[self.modelBook.selectedId] works well, but I don't want to.
Your question is not clear to me so this might be wrong, but hopefully it helps.
bookDetail is not a "copy" in the usual sense, rather it is a reference to the same dictionary that self.modelBook.bookList[self.modelBook.selectedId] references at the time the assignment to bookDetail is made.
Given that you say that using the latter "works well" is sounds as though self.modelBook.selectedId is changing and you expected bookDetail to automatically track that change and now refer to a different dictionary. That is not how assignment works.
How Can I simplify this code?
You could add a property to your modelBook class[1], say currentBook, which returns back bookList[selectedID] so each time it is called you get the current book. In your code above you then use self.modelBook.currentBook instead of self.bookDetail and can remove the property bookDetail as unused (and incorrect).
HTH
[1] Note: this should be called ModelBook to follow naming conventions. Have you noticed the syntax coloring is incorrect? That is because you haven't followed the convention.
Create the shared instance of BookModel then you can access it anywhere:
Write this in bookModel:
+ (instancetype)sharedInstance
{
static bookModel *sharedInstance = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
sharedInstance = [[bookModel alloc] init];
// Do any other initialisation stuff here
});
return sharedInstance;
}
Then you can access this like bookModel.sharedInstance.bookList

Changing Variable in another class iOS

I have follow countless similar situations on here ( stack overflow ). I have applied those write ups for my situation and have come close but haven't found a solution that seems work for me. As this is something very trivial I am baffled at how it isn't working for me.
Anyways, I am trying to set a Int variable from inside the appDelegate class and the variable actually belongs, if that is the right word, to another class (mainViewController).
For the MainViewController class .h file I have
#interface MainWindowControllerViewController :... {
int relayState;
}
#property (readwrite, nonatomic) int relayState;
For the MainViewController class .m file I have
#implementation MainWindowControllerViewController
#synthesize relayState = _relayState;
-(void)quickConnect { // Call for all UI bypassing and quick kill
NSLog(#"Relay state in MainWindow = %d", relayState);
if (_relayState == 1) {
NSLog(#"TURNING ON KILL SWITCH");
self.writeData = [[NSString stringWithFormat:#"%#", #"e"] dataUsingEncoding:NSASCIIStringEncoding];
[sensor write:sensor.activePeripheral data:writeData];
} else {
NSLog(#"TURNING OFF KILL SWITCH");
self.writeData = [[NSString stringWithFormat:#"%#", #"o"] dataUsingEncoding:NSASCIIStringEncoding];
[sensor write:sensor.activePeripheral data:writeData];
}
}
For the appDelegate.h file I have
#import "MainWindowControllerViewController.h"
#interface AppDelegate : UIResponder <UIApplicationDelegate>
{
MainWindowControllerViewController *relayState;
}
#property (nonatomic, assign) MainWindowControllerViewController *relayState;
Then for the appDelegate.m file I have
#import "MainWindowControllerViewController.h"
#implementation AppDelegate
#synthesize relayState = _relayState;
- (BOOL)application:(UIApplication *)application openURL:(NSURL *)url sourceApplication:(NSString *) sourceApplication annotation:(id)annotation {
NSLog(#" Calling application: %#", sourceApplication);
NSLog(#" URL scheme: %#", [url scheme]);
if ([sourceApplication isEqualToString:#"URL-Scheme-Test"]) {
if ([[url scheme] isEqualToString:#"TurnOffRelay"]) {
_relayState =[[MainWindowControllerViewController alloc] init];
_relayState.relayState = 1;
NSLog(#"Relay State BEFORE = %d", _relayState.relayState);
}
return YES;
if ([[url scheme] isEqualToString:#"TurnOnRelay"]) {
_relayState =[[MainWindowControllerViewController alloc] init];
_relayState.relayState = 0;
NSLog(#"Relay State BEFORE = %d", _relayState.relayState);
}
return YES;
}
else
return NO;
}
This is pretty much it. When I do the logs I find that the relayState that I want to change the value of shows that I was able to change the value. But when I do the If statement above that checks weather the relayState is equal to 1 the variable is always 0.
I'm not the most proficient in Obj C. Some help would be appreciated! Thanks. I'll gladly answer any extra questions about code if needed.
You are kind of mixing some older style obj-c with how it usually looks currently and I think you are hiding a variable (one declaration is hiding another)
Take out:
{
int relayState;
}
From your MainWindowControllerViewController interface
Take out the #synthesize in the MainWindowControllerViewController implementation
Don't use _relayState (just use relayState)
Do the same with the MainWindowControllerViewController variable in the AppDelegate.
If that doesn't fix it, we need to see what is happening to the VC you are creating.
The problem I believe is this line
_relayState =[[MainWindowControllerViewController alloc] init];
You are initializing MainWindowControllerViewController in both the if blocks which is resetting the value to the default value (In this case 0) every time.
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:#"Main" bundle:nil];
MainWindowControllerViewController *vc = [storyboard instantiateViewControllerWithIdentifier:#"MainWindowControllerViewControllerIdentifier"];
vc.relayState = 1;
For the MainViewController class .h
#interface MainWindowControllerViewController :... {
int relayState; //remove this line
}
#property (nonatomic) int relayState; //use this
try this
You are making a mistake that will create endless problems for you.
You have a property named relayState and an instance variable named relayState.
The property "relayState" is backed by an instance variable named _relayState. You have another instance variable named relayState. Two different variables. Assigning to self.relayState changes one, assigning to relayState changes the other. Don't do it.
Just get rid of the "int relayState;" and don't use #synthesize and you'll be fine. At least a lot finer than you are now. You can then either use self.relayState or _relayState. At least you will always know what you are doing.
PS. Having an int relayState and a MainWindowViewController* relayState is just asking for trouble. You seem to be intentionally trying to confuse yourself.
PS. You seem to do the same dangerous game with the writeData property/variable.

Pass BOOL value

I am working on an app and I got stuck at the point where I can't seem to retrieve the value of a BOOL set in a class.
I spent too much time already on it, been through all the questions I found that seem to cover the matter.
The bad thing here is that I get something, but not what I need (I get a 0, which means, I guess, that the value wasn't retrieved correctly as it should be 1).
The things I tried are :
pass a pointer to my first class and access to my BOOL like this:
//in some method
self.pointerFirstClass.myBOOL;
NSLog(#"%d", firstClass.myBOOL); => This gives 0!
by declaring it (talking of the pointer) as a property in my second class (and importing the h. file from my first class, where my BOOL is declared as property too):
#property FirstClass *pointerFirstClass;
But I got 0 using this.
The other shot I gave was add my BOOL in the first class and create an instance of the class in my second class
//in some method
FirstClass *firstClass = [[FirstClass alloc] init];
if (firstClass.myBOOL){
//Do something
}
NSLog(#"%d", firstClass.myBOOL); => This gives 0!
But I got 0 too.
As Booleans are primitive types, like in C, I get a bit confused since I am new to object-oriented programming, I don't know how I could like create a getter for this, for example.
I also tried to do a - (BOOL)getBOOLValue method in my first class, and call this method in my second class and assign it to a BOOL in that second class.
But the result wasn't better.
Am I missing something?
Is there a way to get my value that I didn't think of or didn't know about yet?
I am running low on thoughts on how to get around this, it shouldn't be that hard IMO so I hope it is something simple that I just left aside.
EDIT :
Some actual code. I am working between 2 files called AppDelegate (yes, the actual one) and WelcomeViewController (so a VC).
AppDelegate.h
#interface AppDelegate : UIResponder <UIApplicationDelegate>
{
BOOL inRegion; //thought of this making my BOOL as a property of AppDelegate
}
#property (strong, nonatomic) UIWindow *window;
#property BOOL inRegion; //Declaring my BOOL here to make it accessible for another class
- (BOOL)getBOOLValue; //An attempt to pass my BOOL value
AppDelegate.m
- (void)locationManager:(CLLocationManager *)manager didDetermineState:(CLRegionState)state forRegion:(CLRegion *)region
{
if (state == CLRegionStateInside)
{
self.inRegion = YES; //Set my BOOL to TRUE
}
else if (state == CLRegionStateOutside)
{
self.inRegion = NO; //Else set it to False
}
- (BOOL)getBOOLValue
{
return inRegion; //Tried to create a custome "getter"
}
WelcomeViewControler.m (I changed nothing in the .h file)
I said I tried many things, right now, this is the last version of my code.
//Simply trying to do a Segue on a condition...
- (IBAction)onClick:(id)sender {
AppDelegate *appDelegate = [[AppDelegate alloc] init];
if (appDelegate.inRegion) {
[self performSegueWithIdentifier:#"WelcomeToDetection" sender:self];
}
else
{
//Do Nothing
}
}
As said, I want to retrieve the BOOL value of the AppDelegate.
Thank you.
This code doesn't make sense:
self.pointerFirstClass.myBOOL;
NSLog(#"%d", firstClass.myBOOL); => This gives 0!
The first line doesn't do anything. You're not assigning anything to the property, and you're not doing anything with the value. Furthermore, the second line doesn't relate to the first line in any way that we can see from the code you've provided. Try this instead:
self.pointerFirstClass = [[FirstClass alloc] init];
self.pointerFirstClass.myBOOL = YES;
NSLog(#"myBOOL = %d", self.pointerFirstClass.myBOOL);
In other words, you need to be sure that self.pointerFirstClass points to a valid object. And then you need to make sure that you've assigned the value you want to the myBOOL property of that object.
Update: This looks like a case where you're talking to the wrong object. Look at this:
- (IBAction)onClick:(id)sender {
AppDelegate *appDelegate = [[AppDelegate alloc] init];
This is surely not what you really want. The application object is a single object -- a real singleton, in fact, meaning that there is and can be only one application object. That object has a delegate object, and that's a specific instance of your AppDelegate class. In this code, though, you're creating a new instance of AppDelegate, one that's different from the one that the application is using. Any changes that are made to the actual application delegate in response to messages from the application will not be reflected in the new object that you've created.
What I think you want is to get the actual application delegate object, and you can do that using:
[[UIApplication sharedApplication] delegate];
So, change your code to look like this:
- (IBAction)onClick:(id)sender {
AppDelegate *appDelegate = (AppDelegate*)[[UIApplication sharedApplication] delegate];;
if (appDelegate.inRegion) {
[self performSegueWithIdentifier:#"WelcomeToDetection" sender:self];
}
// note: you don't need an else clause if it doesn't do anything
}
That way, you'll be talking to the same object that the app uses, which is the one that has the inRegion property set in response to the location manager call.
UPDATE - Now we can see your code the problem is obvious, you are trying to access the appDelegate by creating a new one...
- (IBAction)onClick:(id)sender {
AppDelegate *appDelegate = [[AppDelegate alloc] init];
Instead you should be doing this....
- (IBAction)onClick:(id)sender {
AppDelegate *appDelegate = [[UIApplication sharedApplication] delegate]
--
Not sure if you are posting your actual code? but the first example you give...
self.pointerFirstClass.myBOOL;
NSLog(#"%d", firstClass.myBOOL); => This gives 0!
Shouldn't the second line be
NSLog(#"%d", self.pointerFirstClass.myBOOL);
Also this property...
#property FirstClass *pointerFirstClass;
Won't retain it once you've set it, it needs to be
#property (nonatomic,strong) FirstClass *pointerFirstClass;
In the second example...
FirstClass *firstClass = [[FirstClass alloc] init];
if (firstClass.myBOOL){
//Do something
}
NSLog(#"%d", firstClass.myBOOL); => This gives 0!
You allocate and initialise a new FirstClass object and then check the property straight away, if you are not setting this to YES in the init then it will be false
Like I say, maybe you're not posting your actual code?
I guess what you want is initializing myBOOL to 1.
If so, you need do something as following
#implement FirstClass
- (id)init
{
self = [super init];
if(self) {
_myBOOL = 1;
}
return self;
}
// Other methods
#end
EDIT:
The comments is why you get 0.
- (IBAction)onClick:(id)sender {
AppDelegate *appDelegate = [[AppDelegate alloc] init]; // this is the problem.
// you create a new appdelegate,
// and never call locationManager:didDetermineState:forRegion:
if (appDelegate.inRegion) {
[self performSegueWithIdentifier:#"WelcomeToDetection" sender:self];
}
else
{
//Do Nothing
}
}
rewrite your code as following:
- (IBAction)onClick:(id)sender {
AppDelegate *appDelegate = [UIApplication sharedApplication].delegate;
if (appDelegate.inRegion) {
[self performSegueWithIdentifier:#"WelcomeToDetection" sender:self];
}
else
{
//Do Nothing
}
}

Variable lost after dismissing modalViewController

I'm using Reachability in my iPad app and discovered some issues when using modalViewControllers.
In my mainViewController I have a BOOL variable determining weather I'm online or not. Here's my code:
// mainViewController.h
BOOL online;
// mainViewController.m
- (void)reachabilityChanged:(NSNotification *)note
{
if([[note object] isReachable]) {
online = YES;
}
else {
online = NO;
}
}
- (void)getOnline
{
NSLog(#"%d", online);
}
// modalViewController.m
#import "mainViewController.h"
- (IBAction)dismissMe
{
mainViewController *main = [[mainViewController alloc] init];
[main getOnline];
[self dismissModalViewControllerAnimated:YES];
}
When I'm calling [self getOnline] within the mainViewController, it returns 1 ('cause I am online).
But: when I'm calling [main getOnline] within the modalViewController, it returns 0 in the log.
Does anybody know why?!
I also tried to put the online variable as a #property into the modalViewController to handle the if online stuff within the modal. But when I assign a value to it (from the main), and log it within the modal, it always returns (NULL).
Hope, you can help me! With best regards, Julian
Short answer: because they use different instances of the online variable.
Long answer: you should only declare BOOL online in the header, not define it. Defining should happen in the .m file, like this:
In the mainViewController.h:
extern BOOL online; // Declare the variable
In the mainViewController.m:
BOOL online; // Define the variable
// the rest of your code
The way your code is written, a separate BOOL online is created for each .m file that includes mainViewController.h; I am sure this is not what you intended.

Resources