Call NSObject method from NSTextField Subclass? - objective-c

I'm having trouble calling an external method from a NSTextField Subclass. I have a NSTextField subclass that I'm monitoring text with and when textDidChange I'm calling an external method that is of a NSObject class. For some reason my method doesn't get called. I'm hoping someone could explain why. My code is below. Thanks.
EDIT: Fixed code to what drewag suggested.
MyTextField.h
#import <Cocoa/Cocoa.h>
#class ObjectController;
#interface MyTextField : NSTextField <NSTextFieldDelegate> {
ObjectController *objectController;
}
#property (strong, nonatomic) ObjectController *objectController;
#end
MyTextField.m
#import "MyTextField.h"
#import "ObjectController.h"
#implementation MyTextField
#synthesize objectController;
- (void)textDidChange:(NSNotification *)notification{
[objectController methodFromOtherClass];
}
#end
ObjectController.h
#import <Foundation/Foundation.h>
#interface ObjectController : NSObject {
}
- (void)methodFromOtherClass;
#end
ObjectController.m
#import "ObjectController.h"
#implementation ObjectController
- (void) methodFromOtherClass {
NSLog(#"Testing");
}

There are two likely scenarios causing this issue:
objectController is nil when textDidChange: is called
textDidChange: is not actually being called because you didn't connect it up correctly.
I don't think anyone can help you beyond that since you did not post your connection code nor where you are setting objectController.

Probably forgot to assign the delegate to self or whatever object that implements the textDidChange? Happens to me a lot.

I fixed the issue by creating an instance of ObjectController instead of the above process.
ObjectController *objectController = [ObjectController new];
[objectController methodFromOtherClass];

Related

do you need to import .h files when using delegates?

-(IBAction)ok
{
//send message to the delegate with the new settings
[self.delegate setHeight:_height Width:_width Mines:_mines];
[self.delegate dismissViewControllerAnimated:YES completion:nil];
}
the first message to the delegate wouldn't work until i imported ViewController.h, but the second one worked without the import.
if i add -(void)setHeight:(int)h Width:(int)w Mines:(int)m; as required in the optionsViewController protocol will that mean that i no longer have to import the root .h file.
i intend to use delegation to send messages in other parts of the program so i want to make sure i am using it correctly and not importing things when i don't need to.
Thank you.
if i add -(void)setHeight:(int)h Width:(int)w Mines:(int)m; as required in the optionsViewController protocol will that mean that i no longer have to import the root .h file.
Yes! You could also add it as #optional and it would work (remember to check if the delegate -respondsToSelector: in that case). The whole idea is that your object regularly knows nothing about the delegate object - except that it conforms to the protocol (ie implements the #required and possibly the #optional methods).
Added for clarification (on my phone, which is a pain in the butt):
//OptionsViewController.h
//this object does NOT have to import
//the calling viewControllers .h file
//which is what I think the OP does
#protocol optionsViewControllerProtocol;
#interface OptionsViewController : UIViewController
#property (nonatomic, assign) id<optionsViewControllerProtocol> delegate; //should be id, could be UIViewController too, if absolutely necessary (better design to make it id)
#end
#protocol optionsViewControllerProtocol <NSObject>
#required
-(void) setHeight: (NSInteger) height;
#end
//viewController.h
#import "optionsViewController.h" //necessary to get the protocols definitions
#interface OptionsViewController: UIViewController <optionsViewControllerProtocol>
//.....
If you define your delegate property to be of class UIViewController*, then the compiler will recognize the dismissViewControllerAnimated:completion: method without you needing to import anything, since that's a standard method for that class.
For a custom method, i.e. setHeight:Width:Mines:, you absolutely need to import the header file, or have it imported somewhere up the import chain.
Example: You have MyProtocol.h, and you want SomeClass to have a delegate property that conforms to that protocol. If you #import "MyProtocol.h" in SomeClass.h, you don't need to re-import it in SomeClass.m.
// SomeClass.h
#import "MyProtocol.h"
#interface SomeClass : NSObject
#property (weak, nonatomic) id<MyProtocol> delegate;
#end
//SomeClass.m
#import "SomeClass.h"
#implementation SomeClass
- (void)someMethod
{
[self.delegate myProtocolMethod];
}
#end

No access to global instance (build by factory) on iOS

this is a follow-up question to my last one here: iOS: Initialise object at start of application for all controllers to use .
I have set my application up as follows (ignore the DB Prefix):
DBFactoryClass // Built a DataManaging Object for later use in the app
DBDataModel // Is created by the factory, holds all data & access methods
DBViewControllerA // Will show some of the data that DBDataModel holds
moreViewControllers that will need access to the same DBDataModel Object
i will go step by step through the application, and then post the problem in the end
AppDelegate.h
#import "DBFactoryClass.h"
AppDelegate.m
- (BOOL)...didFinishLaunching...
{
DBFactoryClass *FACTORY = [[DBFactoryClass alloc ]init ];
return YES;
}
DBFactoryClass.h
#import <Foundation/Foundation.h>
#import "DBDataModel.h"
#interface DBFactoryClass : NSObject
#property (strong) DBDataModel *DATAMODEL;
#end
DBFactoryClass.m
#import "DBFactoryClass.h"
#implementation DBFactoryClass
#synthesize DATAMODEL;
-(id)init{
self = [super init];
[self setDATAMODEL:[[DBDataModel alloc]init ]];
return self;
}
#end
ViewControllerA.h
#import <UIKit/UIKit.h>
#import "DBDataModel.h"
#class DBDataModel;
#interface todayViewController : UIViewController
#property (strong)DBDataModel *DATAMODEL;
#property (weak, nonatomic) IBOutlet UILabel *testLabel;
#end
ViewControllerA.m
#import "todayViewController.h"
#implementation todayViewController
#synthesize testLabel;
#synthesize DATAMODEL;
- (void)viewDidLoad
{
todaySpentLabel.text = [[DATAMODEL test]stringValue]; // read testdata
}
#end
DBDataModel.h
#import <Foundation/Foundation.h>
#interface DBDataModel : NSObject
#property (nonatomic, retain) NSNumber* test;
#end
DBDataModel.m
#import "DBDataModel.h"
#implementation DBDataModel
#synthesize test;
-(id)init{
test = [[NSNumber alloc]initWithInt:4]; // only a testvalue
return self;
}
#end
the app builds fine, and starts up but the label stays blank. so either the object does not exist (but i guess this would result in an error message), or something else is wrong with my setup. any thoughts?
Two notes:
Your have a shotgun approach to asking questions: everytime you hit a stumbling block, you ask a question and if the answer does not work immediately, you ask another one. You have to spend some energy in between the questions debugging and poking into the code on your own, otherwise you will depend on the external help forever.
Use the common coding style please. CAPS are reserved for macros.
Now to the code:
- (BOOL) …didFinishLaunching…
{
DBFactoryClass *factory = [[DBFactoryClass alloc] init];
return YES;
}
This simply creates an instance of the DBFactoryClass and then throws it away. In other words, it’s essentially a no-op. Judging by the comments in the previous answer you create the controllers using the Storyboard feature. How are they supposed to receive the reference to the data model? The reference isn’t going to show up by magic, you have to assign it somewhere.
I’m not familiar with the Storyboard feature. The way I would do it is to create the view controllers using separate XIB files, then you can create the controller instances in the Factory class and pass them the needed reference to the model. In the end the application delegate would create the factory, ask it to assemble the main controller and then set it as the root view controller for the window. Just like in my sample project. It’s possible that there’s a way to make it work with storyboards, but as I said, I am not familiar with them.

Custom delegate

I want to know how can I use a custom delegate?
Maybe an example will help you:
#import <UIKit/UIKit.h>
#protocol VSKeypadViewDelegate
#required
-(int)numberOfRows;
-(int)numberOfColumns;
-(NSString*)titleForButtonOnRow:(int)row andColumn:(int)column;
-(id)valueForButtonOnRow:(int)row andColumn:(int)column;
-(CGSize)sizeForButtonOnRow:(int)row andColumn:(int)column;
-(void)receivedValue:(id)value;
-(CGPoint)keypadOrigin;
#optional
-(NSArray *)additionalButtonsForKeypad;
//-(UIColor *)keypadBackgroundColor;
//-(UIColor *)keyBackgroundColorForRow:(int)row andColumn:(int)Column;
-(UIImage *)backgroundImageForState:(UIControlState)state forKeyAtRow:(int)row andColumn:(int)column;
-(BOOL)isButtonEnabledAtRow:(int)row andColumn:(int)column;
#end
#interface VSKeypadView : UIView {
id<VSKeypadViewDelegate> delegate;
NSArray *keypadButtons;
}
+ (VSKeypadView *)keypadViewWithFrame:(CGRect)r;
- (id)initWithFrame:(CGRect)r ;
-(void)fireKeypadButton:(id)sender;
#property(nonatomic, assign) id<VSKeypadViewDelegate> delegate;
#end
This is a keypad I wrote.
The VSKeyPadView derives from UIView and has a delegate ivar of type id<VSKeypadViewDelegate>, that means, that the object set to delegate is expected to conform to the protocol VSKeypadViewDelegate. That protocol has some required and some optional method. That means, that it is your responsibility to write those method — what ever makes sense for you.
You will find this code running in an example application at github.

Creating Delegate methods in a Protocol

I cannot seem to build my protocol the way I would like and I have narrowed down to a problem with using derived classes. If I use a cocoa class it seems to work. Here is what I have...
#import <Foundation/Foundation.h>
#import "MyView.h"
#protocol MyDelegate
- (void)view:(MyView *)aView didDoSomethingWithString:(NSString *)string;
#end
The MyView class is...
#import <UIKit/UIKit.h>
#interface MyView : UIView {
NSString *whatever;
}
- (void)myMethod;
#end
#implementation MyView
- (void)myMethod {
doSomething...
}
#end
So when I attempt to build I get the error "Expected ')' before 'MyView'". If I replace the custom class MyView with UIView then the code compiles. I am hoping someone sees something that I am overlooking. Any ideas are appreciated.
Thanks.
Are you sure MyView.h contains #interface MyView : UIView?
Also, instead of importing you can use #class. e.g.
#class MyView;
#protocol MyDelegate
- (void)view:(MyView *)aView didDoSomethingWithString:(NSString *)string;
#end
Try putting the #interface and #implementation parts in different files (if you currently have them in the same file). It looks like you have all that in MyView.m, and you're importing MyView.h, which doesn't exist.

Access IBOutlet from other class (ObjC)

I've googled around and found some answers but I didn't get any of them to work. I have one NSObject with the class "A" and a second class "B" without an NSObject. In class "A" are my IBOutlets defined and I can't seem to figure out how to access those outlets from class "B"...
I've found answered questions like http://forums.macrumors.com/archive/index.php/t-662717.html But they're confusing.
Any help would be greatly appreciated!
Simplified Version of the Code:
aClass.h:
#import <Cocoa/Cocoa.h>
#interface aClass : NSObject {
IBOutlet NSTextField *textField;
}
#end
aClass.m:
#import "aClass.h"
#implementation aClass
// Code doesn't matter
#end
bClass.h:
#import <Cocoa/Cocoa.h>
#interface bClass : NSObject {
}
#end
bClass.m:
#import "aClass.h"
#import "bClass.h"
#implementation bClass
[textField setStringValue: #"foo"];
#end
When you write:
I have one NSObject with the class
"A" and a second class "B" without an
NSObject.
It tells me that you don't have your head around the basic concepts.
Read through Apple's objective-C introduction, and the tutorial projects.
The solution is using NSNotificationCenter. Here's a thread telling you how to do it: Send and receive messages through NSNotificationCenter in Objective-C?
Then in the method reacting to the notification, you call a method accessing the Outlet
- (void) receiveTestNotification:(NSNotification *) notification
{
if ([[notification name] isEqualToString:#"TestNotification"])
//NSLog (#"Successfully received the test notification!");
[self performSelectorOnMainThread:#selector(doIt:) withObject:nil waitUntilDone:false];
}
- (void) doIt
{
//testLabel.text = #"muhaha";
}
This worked for me, I hope it does so for you as well.