Setting Delegate and Lazy instantiation - objective-c

I have an App with an NSWindowController and an associated XIB which is not needed most of the time (admin interface window), so I wanted to use Lazy instantiation. However, I also need to setup the 'delegate' and that is when the errors happen.
I have everything setup in the AdminWindow,h (subclass of `NSWindowController') and .m file.
In my main controller, MainController (subclass of NSObject) I have the following working code.
#interface MainController : NSObject<AdminWindowDelegate>{
AdminWindow *myAdminWindow;
}
#implementation MainController
-(id)init{
myAdminWindow = [[AdminWindow alloc] init];
[myAdminWindow setDelegate:self];
}
-(IBAction)openAdminWindow:(id)sender{
[myAdminWindow showWindow:nil];
}
So that all works, but I don't want to instantiate myAdminWindow until it's needed, thought lazy instantiation would work.
Altered the MainController:
#implementation{
-(AdminWindow *) myAdminWindow{
if(!_myAdminWindow){
_myAdminWindow = [[AdminWindow alloc] init];
//Tried to set delegate here, but does not work
}
-(IBAction)openAdminWindow:(id)sender{
[self.myAdminWindow showWindow:nil];
}
Where do I set the delegate? I tried just after 'alloc' 'init' of myAdminWindow, but it does not work. when I start typing the command
_myAdminWindow.setDe... Xcode gives nothing, .setDelegate or .delegate are not options.
I've tried
[_myAdminWindow setDelegate Nope, does not work either.
Leaving out the delegate portion, everything else works as desired.
Question: When using lazy instantiation , where do I set the delegate? and how?
Thank you in advance
===[EDIT]===
In case someone else has the same question.
Thank you to Phillip Mills for the reply and reminder.
I removed the following declaration in #interface of MainController:
AdminWindow *myAdminWindow;
And declared myAdminWindow in the MainController's interface section as a property - and all is good!

Related

No visible #interface for 'SwiftController' declares the selector (from objective-c class)

I have an init method in Swift and I tried to call it from Objective-C class. But there is an error written "No visible #interface for 'NoteViewController' declares the selector 'initWithModel:withKeyboardType:'"
I add "target-Swift.h" and it's 100% correct because I already put it on another class and its works well. I've put #objc and make the init method modifier become public
this is the import
#import "gp27appj-Swift.h"
this is the init method
#objc public init(model: NoteViewModel, with keyboardType: tagKeyboardType) {
super.init(model: model)
self.keyboardType = keyboardType
}
this is how I called from objective-c
viewController = [[NoteViewController alloc] initWithModel:noteViewModel withKeyboardType:(tagKeyboardType)gameContext.selectedAnswerType];
I expect everything works well because I already put everything in the right place. Thank you
---------- SOLVED thanks to #rmaddy
it's a silly mistake because the completion doesn't show up before
instead of
viewController = [[NoteViewController alloc] initWithModel:noteViewModel withKeyboardType:(tagKeyboardType)gameContext.selectedAnswerType];
I should use
viewController = [[NoteViewController alloc] initWithModel:noteViewModel with:(tagKeyboardType)gameContext.selectedAnswerType];

Message sent to deallocated instance using ARC

I wouldn't normally ask questions like this, but I really cant get my head around it. I have a class 'GetTableInfoFromDatabase', which connects to my database and downloads some JSON. This works great from the first screen of my tab-bar application. I can call the getNewData method as much as I want to effectively refresh the data.
My problem arises when I try and create an instance of the 'GetTableInfoFromDatabase' class and call the very same method from another tab. I get the following error:
*** -[GetTableInfoFromDatabase respondsToSelector:]: message sent to deallocated instance 0x1d89e830
The funny thing is, i'm using ARC. The culprit (in my opinion) is ASIHTTPRequest. I have had to enable -fno-objc-arc to get the project to compile. This library is used in the GetTableInfoFromDatabase class.
Here is the class:
- (void) getEventDataWithSender:(id)sender{
ASIHTTPRequest *request = [ASIHTTPRequest requestWithURL:[NSURL URLWithString:#"-------.com/getdata.php"]];
[request setDelegate:self];
NSLog(#"Running!");
[request startAsynchronous];
AppDelegate *appDelegate = (AppDelegate *)[[UIApplication sharedApplication] delegate];
self.managedObjectContext = appDelegate.managedObjectContext;
}
And this is how i'm calling it:
GetTableInfoFromDatabase *getInfo = [[GetTableInfoFromDatabase alloc]init];
[getInfo getEventDataWithSender:self];
I've even changed the order of the tabs around, so the first tab to be displayed purely just calls this method, nothing else. Not even before the 'GetTableInfoFromDatabase' has been previously initialised by the class that initialised it first last time. Still crashes.
Has anyone got any ideas? This is so frustrating!
You need to assign that variable to a property if you plan on exposing it to other view controllers. ARC will, and should, immediately deallocate getInfo after this code executes:
GetTableInfoFromDatabase *getInfo = [[GetTableInfoFromDatabase alloc]init];
[getInfo getEventDataWithSender:self];
So if this line is included in say viewDidLoad: and nothing else refers to getInfo in that method, it will be immediately released. Why, because you haven't told the compiler that it should retain it.
So in the view controller that's exposing this class, on whatever tab it might be a child of... you would do something like this:
ViewController.h
#class GetTableInfoFromDatabase; // forward declaration
#interface ViewController : UIViewController
#property (strong, nonatomic) GetTableInfoFromDatabase *getInfo;
ViewController.m
#implementation ViewController
#synthesize getInfo = _getInfo;
- (void) viewDidLoad {
[super viewDidLoad];
self.getInfo = [[GetTableInfoFromDatabase alloc]init]; // assign your value to a property
[self.getInfo getEventDataWithSender:self];
}
So when you declare your property as Strong in your header, it will maintain a strong reference to it. #Synthesize getInfo = _getInfo means that it will create a getter and setter for self.getInfo around an instance variable named _getInfo. If you didn't want to expose it as a property, just an instance variable... you could do this:
ViewController.h
#class GetTableInfoFromDatabase; // forward declaration
#interface ViewController : UIViewController {
GetTableInfoFromDatabase _getInfo;
}
ViewController.m
#implementation ViewController
- (void) viewDidLoad {
[super viewDidLoad];
_getInfo = [[GetTableInfoFromDatabase alloc]init]; // assign your value to a property
[_getInfo getEventDataWithSender:self];
}
By default, the compiler will maintain a strong reference to that instance variable unless otherwise specified. You can have weak references as well, and all of those options are pretty well documented. So with ARC, or plain old memory management in general, you need to make an instance variable or property if you want it to hang around for a while.
Honestly... all ARC is doing for you is keeping you from having to call retain and release. Before ARC, setting that property would look like this:
GetTableInfoFromDatabase getInfo = [[GetTableInfoFromDatabase alloc]init];
self.getInfo = getInfo;
[getInfo release];
Now with ARC, the compiler just writes that code for you ;) Hope this helps!
[self.getInfo getEventDataWithSender:self];
Your GetTableInfoFromDatabase object is being deallocated, almost certainly because nothing is holding a strong reference to it. In your code above, getInfo is a local variable, so I would expect it to be released very shortly after this code, unless you are storing it somewhere.
Almost certainly, your dealloc in GetTableInfoFromDatabase does not clear the request's delegate. You should be holding the request in an ivar of GetTableInfoFromDatabase so that it can remove itself as delegate when it is deallocated.
As a side note, avoid prefacing ObjC methods with get. That has a special meaning in KVC (it means that the first parameter is supposed to be updated by reference). Typically the kind of method you have here would be prefaced with "fetch."

ios warning calling init method of a uiviewcontroller

I have my custom viewcontroller declared like this:
#interface DetailViewControllerSpeciality2 : UIViewController <UITableViewDelegate, UITableViewDataSource> {
}
and I create a new instance like this:
DetailViewControllerSpeciality2 *detailViewControllerSpeciality = [[DetailViewControllerSpeciality2 alloc] init];
but xcode tell me a warning:
multiple methods named '-init' found
but I don't have declared a -init method...
You aren't showing all the error message, nor the relevant code. Still, there is enough evidence to make an educated guess.
More likely than not, you have an init method declared like:
- (DetailViewControllerSpeciality2 *) init;
The compiler is complaining because that conflicts with NSObject's init (that returns id).
Declare your init to return id and the compiler should be happy. If that isn't the problem, post more code.
try this.
[[DetailViewControllerSpeciality2 alloc] initWithNibName:nil bundle:nil];

in objective-c initializing an object and giving it an instance name

in cocos2d-iphone I have a CCLayer class called GameScene
I want to use this class from another class however I dont know the name of the instance of the GameScene class
I initialized an instance of GameScene class as follows
-(id) init {
if ((self = [super init])) {
however this will not give me the name of the instance
I read in documentation that a method called initWithName can be used so I tried something like this but it does not work it gives me warning:
In function '-[GameScene init]':
warning: 'CCLayer' may not respond to '-initWithName:'
the code I tried is
-(id) init {
if ((self = [super initWithName:"gamescene"])) {
I will need only one instance of this class through the game but I cant catch a handler of that instance so I can use it from other classes?
any Idea
Many Thanks
update:
Hello
I am going to update the code to let you know that I have tried your solution but it dosnot seem to work yet
in the MyAppDelegate.h I have this lines of code:
firstly I have defined the app delegate to share it with other classes
MyAppDelegate.h
#define AD (MyAppDelegate *)[[UIApplication sharedApplication] delegate]
and in the MyAppDelegate.m I have the following code:
gs = [[GameScene alloc] init];//this is the gamescene
sc = [gs scene]; //this calls the method -(id)(scene)
[[CCDirector sharedDirector] runWithScene: sc]; //runwithscene
now when I tried to use the gs within other class -for example player.m class-
player.m
GameScene* gs = [AD gs]; //retrieving the instance from appdelegate
[gs updateScoreByAmount:5];/calling the method "updateScoreByAmount"
the results , guess what happens?
the program runs without errors however gs instance seems to be different than the one which is run by the appdelegate since this method "updateScoreByAmount" does not affect the scene which run by the runWithScene in the appdelegate
any idea?
Many Thanks to all those who have tried to help
If I am understanding you correctly, you need a reference to an instance of the GameScene class? If that is the case, it depends how the object is created. You probably are creating the instance from some controller class and it would look something like:
GameScene *gameScene = [[GameScene alloc] init];
Here, gameScene would be the reference to the instance you need.
ahmed,
Instead of storing a pointer to your top level scene, you can do this to get access to it:
GameScene* myScene = (GameScene*)[[CCDirector sharedDirector] runningScene];
CCDirector is a singleton, and it knows what scene it's currently running, so you don't need to keep a pointer to it, you can use the above way of getting to it when you need it.
Because GameScene is a child of CCScene your running scene will be your GameScene object.
Hope that helps.

Can't access UI from a delegate?

I got this code:
GrooveOnDownload *dlg = [[GrooveOnDownload alloc] init];
NSURLDownload *dw = [[NSURLDownload alloc] initWithRequest:request delegate:dlg];
It starts the download in a delegate class with outlets for UI controls. But for some reason controls don't respond to direct messages from the delegate.
//Header of the delegate
#interface GrooveOnDownload : NSObject {
IBOutlet id downloadButton;
//...
//Implementation
//...
[downloadButton setEnabled:FALSE]; // Doesn't work
//...
Any ideas?
It is my fourth day of Mac development so I don't know much about the platform.
Edit : 2010-05-28 01:03:41.486 GrooveOnLite[3303:a0f] Download button = (null)
Edit 2 :
Edit 3 :
I miss Windows .....
Edit 4
In Win32 you send one window message to the button. Everything is handled by WndProc loop. It is damn simple. In Mac you have this magical interface builder which somehow gets all that crap working. The delegate gets called by some withcraft magic. The rest of the classes are connected by some 'magical' force. In windows there is an tmain function which is the entry point. That's it! No retarded outlets and such shit.
I know it sounds obvious, but is everything connected correctly in Interface Builder?
Edit
If the download is on a separate thread, then fbrereto is correct and you'll need to perform the selector on the main thread. Your code would need to be changed to look like this:
[downloadButton performSelectorOnMainThread:#selector(setEnabled:)
withObject:[NSNumber numberWithBool:NO]
waitUntilDone:YES];
A few notes: in Objective-C the keyword NO is used instead of FALSE. It's a primitive type, so in order to use it here we had to box it in a NSNumber object. The waitUntilDone argument does exactly what you would expect, and you can change that to NO if you'd rather not wait.
Edit 2
Here's a more complete code example about how to accomplish what I think you want, which is to reuse a single instance of GrooveOnDownload from your app delegate. I'm assuming that your app delegate class is called GrooveOnLiteAppDelegate.
// GrooveOnLiteAppDelegate.h
#interface GrooveOnLiteAppDelegate : NSObject
{
IBOutlet GrooveOnDownload *grooveOnDownload;
// other properties go here
}
// your method signatures go here
#end
// GrooveOnLiteAppDelegate.m
#implementation GrooveOnLiteAppDelegate
- (void)mySuperAwesomeMethod
{
// it's up to you to figure out what method to put this in and
// how to call it
NSURLDownload *dw = [[NSURLDownload alloc] initWithRequest:request delegate:grooveOnDownload];
}
#end
Given that code in your app delegate, you'll have an outlet in IB that you can connect to your GrooveOnDownload object in IB. If you do that, then grooveOnDownload will be a pointer to that object.
All UI calls have to be made on the main thread; if the download is happening in the background your delegate may be getting notified on a thread other than the main one, in which case a call to a UI element would have to be done through something like -[NSObject performSelectorOnMainThread:withObject:waitUntilDone:modes: or another related API.