add property to NSApplication/NSResponder causes error on macOS app - objective-c

I am trying to migrate one iOS app to macOS, the code below work!
AppDelegate.h
#import <UIKit/UIKit.h>
#interface AppDelegate : UIResponder <UIApplicationDelegate>{
}
#property (nonatomic, assign) NSInteger myProperty;
#end
RootController.h
#import <UIKit/UIKit.h>
#interface RootController : UIViewController{}
#property (strong,nonatomic) AppDelegate *appDelegate;
#end
RootController.m
appDelegate =(AppDelegate *)[[UIApplication sharedApplication] delegate];
appDelegate.myProperty=5;
so I set the similar code on macOS app
AppDelegate.h
#import <AppKit/AppKit.h>
#import <CoreData/CoreData.h>
#import <Cocoa/Cocoa.h>
#interface AppDelegate :NSResponder <NSApplicationDelegate>{
}
#property (nonatomic, assign) NSInteger myProperty;
#end
AppDelegate.m
#import "AppDelegate.h"
#implementation AppDelegate
#synthesize myProperty;
#end
AppController.h
#import "AppDelegate.h"
#interface AppController : NSWindowController <>{
}
#property (strong,nonatomic) AppDelegate *appDelegate;
#end
AppController.m
//..
appDelegate =(AppDelegate *)[[NSApplication sharedApplication] delegate];
appDelegate.myProperty=5;//
cause error
[AppController setMyProperty:]: unrecognized selector sent to instance 0x7f8992b4a280
your comment welcome

Related

EXEC_BAD_ACCESS when clicking on a button in objective C

I am just learning and trying to put forth some of the knowledge with objective c and cocoa. I have a little program that has a login screen which then displays a main menu. On the main menu view, there is a button that should load a view to be able to add some data to the app. When I click on the button, it doesn't fire the IBAction but throws an error
EXC_BAD_ACCESS [StartMenuViewController performSelector:withObject:]: message sent to deallocated instance 0x6080195e9f90
I know that it is because there is an object that is not instantiated when the message is being sent, but I cannot find out why. Sorry for the code and the novice level here is the main menu view controller StartMenuViewController.m file:
#import "StartMenuViewController.h"
#import "AppDelegate.h"
#import "MasterViewController.h"
#interface StartMenuViewController ()
#end
#implementation StartMenuViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do view setup here.
}
-(IBAction)showStrainView:(id)sender{
AppDelegate *delegate = nil;
delegate = (AppDelegate *)[[NSApplication sharedApplication] delegate];
MasterViewController *addStrainView = [[MasterViewController alloc] initWithNibName:#"MasterViewController" bundle:nil];
[delegate swapView:self.view toView:addStrainView.view];
}
#end
here is the StartMenuViewController.h
#import <Cocoa/Cocoa.h>
#interface StartMenuViewController : NSViewController
#property (weak) IBOutlet NSButton *showStrainViewButton;
#end
Here is the AppDelegate.h
#import <Cocoa/Cocoa.h>
#class loginView, MasterViewController,StartMenuViewController;
#interface AppDelegate : NSObject <NSApplicationDelegate>{
loginView *loginView;
MasterViewController *masterViewController;
}
#property (assign) IBOutlet NSWindow *window;
#property (readonly, strong, nonatomic) NSManagedObjectContext *managedObjectContext;
#property (readonly, strong, nonatomic) NSManagedObjectModel *managedObjectModel;
#property (readonly, strong, nonatomic) NSPersistentStoreCoordinator *persistentStoreCoordinator;
#property (strong) loginView *loginView;
#property (strong) MasterViewController *masterViewController;
#property (strong) StartMenuViewController *starMenuViewController;
-(void)swapView:(NSView *)view1 toView:(NSView *)view2;
#end
Here is the AppDelegate.m
#import "AppDelegate.h"
#include "MasterViewController.h"
#import "ScaryBugDoc.h"
#import "Strains.h"
#import "loginView.h"
#interface AppDelegate()
#end
#implementation AppDelegate
#synthesize managedObjectContext = _managedObjectContext;
#synthesize managedObjectModel = _managedObjectModel;
#synthesize persistentStoreCoordinator = _persistentStoreCoordinator;
#synthesize loginView;
#synthesize masterViewController;
#synthesize starMenuViewController;
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
{
// 1. Create the master View Controller
self.loginView = [[loginView alloc] initWithNibName:#"loginView" bundle:nil];
// 2. Add the view controller to the Window's content view
[self.window.contentView addSubview:self.loginView.view];
self.loginView.view.frame = ((NSView*)self.window.contentView).bounds;
}
-(void)swapView:(NSView *)view1 toView:(NSView *)view2{
//[view1 removeFromSuperview];
[self.window.contentView addSubview:view2];
view2.frame = ((NSView*)self.window.contentView).bounds;
}
#end
If you need the loginView.h and loginView.m files I can add them as well. I would appreciate any and all help. Thanks in advance
The problem is here:
MasterViewController *addStrainView = [[MasterViewController alloc]initWithNibName:#"MasterViewController" bundle:nil];
[delegate swapView:self.view toView:addStrainView.view];
You don't keep a reference to the MasterViewController so it gets deallocated even though its view is kept around. Now anytime the view tries to access methods from the view controller, things fail.
You should make addStrainView a child view controller of self in the above code so the view controller sticks around as long as its view.

Setting up the App Delegate to Manage Data

I'm working on an app with a Split View controller and would like to store the main data class in the App Delegate so I can access it from multiple views (MasterView, DetailView, and several PopUps).
I'm a bit of a noob and can't figure out why Im getting the error:
AppDelegate.m:31:26: Property 'dataController' not found on object of type 'MasterViewController'
Below is the relevant code - any help is much appreciated. Thanks.
AppDelegate.h
#import <UIKit/UIKit.h>
#class EventClassDataController;
#class MasterViewController;
#interface AppDelegate : UIResponder <UIApplicationDelegate>
#property (strong, nonatomic) UIWindow *window;
#end
AppDelegate.m
#import <UIKit/UIKit.h>
#class EventClassDataController;
#class MasterViewController;
#interface AppDelegate : UIResponder <UIApplicationDelegate>
#property (strong, nonatomic) UIWindow *window;
#end
MasterViewController.h
#import <UIKit/UIKit.h>
#class DetailViewController;
#class EventClassDataController;
#interface MasterViewController : UITableViewController
#property (strong, nonatomic) EventClassDataController *dataController;
#property (strong, nonatomic) DetailViewController *detailViewController;
#end
MasterViewController.m
#import "MasterViewController.h"
#import "DetailViewController.h"
#import "EventClassDataController.h"
#import "EventClass.h"
#interface MasterViewController ()
#end
#implementation MasterViewController
#synthesize detailViewController, dataController;
- (void)awakeFromNib
{
self.clearsSelectionOnViewWillAppear = NO;
self.contentSizeForViewInPopover = CGSizeMake(320.0, 600.0);
[super awakeFromNib];
// Initialize event data
self.dataController = [[EventClassDataController alloc] init];
}
EventClassDataController.h
#import <Foundation/Foundation.h>
#class EventClass;
#interface EventClassDataController : NSObject
#property (nonatomic, copy) NSMutableArray *masterEventList;
-(NSUInteger)countOfList;
-(EventClass *)objectInListAtIndex:(NSUInteger)theIndex;
-(void)addNewEvent:(EventClass *)event;
-(void)removeEvent:(EventClass *)event;
#end
You need to add
#import "MasterViewController.h"
to AppDelegate.m.
Explantation:
From your error message I can tell that you're trying to access a property of MasterViewController on line 26 of your AppDelegate. However, in your AppDelegate class you only have a forward declaration ("#class MasterViewController") and you don't include the actual header file for MasterViewController. What this means is that AppDelegate knows there exists a class named MasterViewController somewhere in your project... but that's all it knows. AppDelegate doesn't know anything about the contents of MasterViewController, i.e. properties or methods MasterViewController declares.
The reason to use #class in a header file is so that you can have properties in an #interface such as
#property (nonatomic, strong) MasterViewController * appDelegatesReferenceToMasterViewController;
without having to import MasterViewController.h in AppDelegate.h. This way, other files in your project can import AppDelegate.h without also inadvertently importing MasterViewController.h.
Translation:
You writing the code:
#class MasterViewController;
is like saying to the compiler:
Yo... compiler. I'm going to be talking about something called MasterViewController in this header file and you don't know what a MasterViewController is... but don't trip out bro. It's all good.
But then, later in the .m file after you write the code:
... masterViewController.dataController ...
the compiler responds:
Whoa, whoa, whoa. I was cool with you just having a variable with the type MasterViewController in the header file because you told me it was all good and not to worry. But now here you are trying to use some aspect of MasterViewController that I know nothing about. How am I supposed to know if this is legal or not? Not cool bro.

Delegate won't work

I have a simple delegate test, but for some reason it doesn't get called.
I want to call -(void)test from AppDelegate class via delegate.
/// AppDelegate.h
#import <Cocoa/Cocoa.h>
#protocol AppDelegateDelegate
#required
-(void)test;
#end
#interface AppDelegate : NSObject <NSApplicationDelegate> {
id<AppDelegateDelegate> _delegate;
}
#property(nonatomic, retain) id<AppDelegateDelegate> delegate;
#end
/// AppDelegate.m
#import "AppDelegate.h"
#implementation AppDelegate
#synthesize delegate = _delegate;
-(void)awakeFromNib {
[_delegate test];
}
#end
/// test.h
#import <Foundation/Foundation.h>
#import "AppDelegate.h"
#interface test : NSObject <AppDelegateDelegate>
-(void)test;
#end
/// test.m
#import "test.h"
#implementation test
-(void)test {
//this should be called from AppDelegate
NSLog(#"delegate test");
}
#end
You are calling the delegate test method as soon as the AppDelegate class is loaded and no other class has had a chance to set themselves as the delegate. You need to call the delegate method after another class has had a chance to set itself as the delegate.
Also your delegate property should be defined as:
#property (assign) IBOutlet id <AppDelegateDelegate> delegate;

Call Function When WebView Changes

So, I've been looking at the documentation and Googling, but I can't figure out how to call a method when my WebView (OSX, not iOS), changes... All the examples seem to be for iOS. My code looks like this:
SNAFAppDelegate.h
#import <Cocoa/Cocoa.h>
#import <WebKit/WebKit.h>
#interface SNAFAppDelegate : NSObject <NSApplicationDelegate>
#property (assign) IBOutlet NSWindow *window;
#property (assign) IBOutlet WebView *browser;
- (IBAction)forwards:(id)sender;
#end
SNAFAppDelegate.m
#import "SNAFAppDelegate.h"
#implementation SNAFAppDelegate
#synthesize window = _window;
#synthesize browser = _b;
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
{
[[_b mainFrame] loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:#"https://google.com"]]];
}
#end
SNAFBrowser.h
#import <Cocoa/Cocoa.h>
#import <WebKit/WebView.h>
#import <WebKit/WebFrame.h>
#import <WebKit/WebEditingDelegate.h>
#import <WebKit/WebKit.h>
#interface SNAFBrowser : WebView
#property (assign) IBOutlet WebView *browser;
#end
SNAFBrowser.m
#import "SNAFBrowser.h"
#implementation SNAFBrowser
#synthesize browser = _b;
- (void)webViewDidChange:(NSNotification *)notification
{
NSLog(#"Hello World");
}
#end
Then, in my MainMenu.xib file, I linked the Outlet "browser" from the AppDelegate to the WebView and set the WebView's custom class to SNAFBrowser.
Essentially, I just want to know when the webview loads another page.
I'm probably doing something ridiculously stupid, so any help is appreciated.
Implement the WebFrameLoadDelegate protocol, and see which methods are suitable to implement, for example webView:didFinishLoadForFrame:.
Example:
#interface SNAFBrowser : WebView <WebFrameLoadDelegate>
...
#end
#implementation SNAFBrowser
- (void)webView:(WebView *)sender didFinishLoadForFrame:(WebFrame *)frame
{
NSLog(#"Something got loaded!");
}
...
#end

Objective C: "Property implementation must have its declaration in interface"

I have the following code:
//RootViewController.h:
#import <UIKit/UIKit.h>
#interface RootViewController : UIViewController{
IBOutlet UITextField *login_uname;
IBOutlet UITextField *login_pword;
IBOutlet UIActivityIndicatorView *login_thinger;
IBOutlet UIImageView *logo;
IBOutlet UISwitch *login_remember;
IBOutlet UIScrollView *scrollView;
}
-(IBAction) login_submitClick:(id)sender;
-(IBAction) doneEditing:(id)sender;
-(IBAction) clearPword:(id)sender;
-(void) showSignUp:(id)sender;
-(void)doLogout:(id)sender;
//for file handling:
-(NSString *)documentsPath;
-(NSString *)readFromFile:(NSString *)filePath;
-(void) writeToFile:(NSString *)text withFileName:(NSString *) filePath;
#end
//RootViewController.m
#import "RootViewController.h"
//#import "Main.h"
//#import "SignUp.h"
#import "ASIHTTPRequest.h"
#import "ASIFormDataRequest.h"
#import "CommonCrypto/CommonHMAC.h"
#import "Details.h"
//#import "signUpSMS.h"
#import "JSON.h"
#implementation PrestoCab3ViewController
#synthesize login_uname; //this line throws the error in the title
...
I'm using XCode 4.1 and was wondering if someone could please help me get to the bottom of this error. I'm very new to XCode.
Many thanks in advance,
You need to declare the property with #property in your interface.
#property( nonatomic, retain ) IBOutlet UITextField * login_uname;
Here, non-atomic is used because it's an IBOutlet.
Also note the property has the retain modifier, meaning you are responsible to release the object when you don't need it anymore.