Creating Delegate methods in a Protocol - objective-c

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.

Related

Objective C run 'private' method defined in one .mm file from another .mm file

There are many questions about accessing 'private' (I hear technically there is no such thing as a private method in Obj-C) messages in Obj-C. And there are many questions addressing No visible #interface for SomeClass declares the the selector 'SomeMethod'. However, there is not one that addressed both.
So here is some code.
Example.h
#import <Cocoa/Cocoa.h>
#interface Example : NSView
#end
Example.mm
#import "Example.h"
#interface Example()
- (void) printWordOne:(NSString*) firstWorld wordTwo:(NSString*) secondWord;
#end
#implementation Example
- (void)drawRect:(NSRect)dirtyRect {
[super drawRect:dirtyRect];
// Drawing code here.
}
- (void) printWordOne:(NSString*) firstWorld wordTwo:(NSString*) secondWord{
NSLog(#"The two words are %# %#", firstWorld, secondWord);
}
#end
ViewController.h
#import <Cocoa/Cocoa.h>
#import "Example.h"
#interface ViewController : NSViewController{
IBOutlet Example *example;
}
#end
The IBOutlet has been connected in storyboard.
ViewController.mm
#import "ViewController.h"
#implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
[example printWordOne:#"Hello" wordTwo: #"World"];
}
- (void)setRepresentedObject:(id)representedObject {
[super setRepresentedObject:representedObject];
// Update the view, if already loaded.
}
#end
The issue I am having is with this method call.
[example printWordOne:#"Hello" wordTwo: #"World"];
The error is No visible #interface for 'Example' declares the selector 'printWordOne:wordTwo'
I need a way to call that function without declaring it in the Example.h file. If I #import Example.mm in my ViewController.mm file I get the following:
duplicate symbol _OBJC_CLASS_$_Example in:
/path/Example.o
/path/ViewController.o
duplicate symbol _OBJC_METACLASS_$_Example in:
/path/Example.o
/path/ViewController.o
ld: 2 duplicate symbols for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)
I know using class_copyMethodList I can get the method list and list that method from ViewController.mm. But again is there anyway to execute the method.
Any help would be greatly appreciated.
You can simply declare category to Example class with private method declaration inside your ViewController.mm:
#import "ViewController.h"
#interface Example()
- (void) printWordOne:(NSString*) firstWorld wordTwo:(NSString*) secondWord;
#end
#implementation ViewController
// ...
#end

Call NSObject method from NSTextField Subclass?

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

iOS5, StoryBoards, ARC: Weird categories issue

I've created a file with sql methods and now this file is really large. I'd like to split it for best practice and implementation simplicity. So, categories.
I've created in xCode new objective-c categories file -> DBAccess+Generals.h (.m).
.h:
#import "DBAccess.h"
#interface DBAccess (Generals)
-(void)newMeth;
#end
.m
#import "DBAccess+Generals.h"
#import "DBAccess.h"
#implementation DBAccess (Generals)
-(void)newMeth
{
NSLog(#"New Meth");
}
#end
In DBAccess.h
#import <Foundation/Foundation.h>
#import <sqlite3.h>
#import "DBAccess+Generals.h"
#interface DBAccess : NSObject
{
NSString *databaseName;
}
#property(nonatomic,strong)NSString *databaseName;
DBAccess.m
#import "DBAccess.h"
#import "DBAccess+Generals.h"
#implementation DBAccess
#synthesize databaseName;
sqlite3* database=nil;
-(id)init
{
if ((self=[super init]))
{
//[self initializeDataBase];
databaseName=#"world_coins.db";
//firstVerDB=#"ac_ch_ver.1.0.db";
}
return self;
}
//Tones of methods
#end
Looks like the code is OK. Getting error "interface implementation not found for DBAccess". I've googled and stackoverflowed around, but the issues described, are not my case.
any help? Thank you in advance.
The problem is the cyclic import
#import "DBAccess+Generals.h" in DBAccess.h
#import "DBAccess.h" in DBAccess+Generals.h
If you remove the first one, the code compiles.

Move Delegates to their own classes?

My view controller is getting a little large for me. I'm implementing five delegate protocols and was about to add a sixth.
ABCViewController : UITableViewController<NSFetchedResultsControllerDelegate,
UITableViewDelegate,
UITableViewDataSource,
UIAlertViewDelegate,
CLLocationManagerDelegate>
One controller to implement them all seems ridiculous, but they aren't being used anywhere else. Should these be in their own classes or in the view controller?
You could add categories to ABCViewController, like this:
1. Move any declarations in ABCViewController.m into a private category in ABCViewController.h
// in ABCViewController.h
#interface ABCViewController : UIViewController <delegates>
// anything that's in the _public_ interface of this class.
#end
#interface ABCViewController ()
// anything that's _private_ to this class. Anything you had defined in the .m previously
#end
2. ABCViewController.m should include that .h.
3. Then in ABCViewController+SomeDelegate.h and .m
// in ABCViewController+SomeDelegate.h
#interface ABCViewController (SomeDelegateMethods)
#end
// in ABCViewController+SomeDelegate.m
#import "ABCViewController+SomeDelegate.h"
#import "ABCViewController.h" // here's how will get access to the private implementation, like the _fetchedResultsController
#implementation ABCViewController (SomeDelegateMethods)
// yada yada
#end
You can also declare conformity to that protocol in the .m file like this:
#interface ABCViewController (NSFetchedResultsControllerDelegateMethods) <NSFetchedResultsControllerDelegate>
#end
#implementation ABCViewController (NSFetchedResultsControllerDelegateMethods)
...
#end
This won't make your file shorter but at least it will be clearly divided into parts
If you are using Xcode you can try something like this for example:
#pragma mark - NSFetchedResultsControllerDelegateMethods
Quite handy to find your methods like in this tip: Pragma mark
Alternatively, depending on what you do the delegate methods and how structured is your code you could have another object that has only methods of the delegate protocol
#interface Delegate <NSFetchedResultsControllerDelegate> : NSObject
#end
You would have an instance of this object as an ivar in your ABCViewController.

Error when declaring delegate property

This should be an easy question - but I'm having a hard time figuring it out. I'm trying to create a property on an object so that during prepareForSegue I can tell the object what it's delegate is. I know I could do this with protocols but I figured for this case a direct approach would be simplest. Unfortunately, the following code results in a compiler error:
#import <UIKit/UIKit.h>
#import "PlanningViewController.h"
#interface DepartmentViewController : UITableViewController
#property (nonatomic, weak) PlanningViewController *planningDelegate;
#end
When I type the property declaration, Xcode recognizes PlanningViewController and even displays the text for me to just tab through. The compiler, though, complains with:
Unknown type name 'PlanningViewController': did you mean 'UISplitViewController'?
What am I doing wrong?
PlanningViewController.h looks like this:
#import <UIKit/UIKit.h>
#import "DepartmentViewController.h"
#interface PlanningViewController : UITableViewController
// Table cell connections
- (IBAction)addItemPressed:(id)sender;
#end
Remove this line from your PlanningViewController.h header file:
#import "DepartmentViewController.h"
You have something of a loop in your header files.
Better still, make DepartmentViewController.h look like this (there is no need to include PlanningViewController.h in your header file):
#import <UIKit/UIKit.h>
#class PlanningViewController;
#interface DepartmentViewController : UITableViewController
#property (nonatomic, weak) PlanningViewController *planningDelegate;
#end
I think you've kind of missed one of the main points of the delegate patter which is to decouple you objects. The best way of declaring this delegate would be:
#import <UIKit/UIKit.h>
#protocol DepartmentViewControllerDelegate; // forward declaration of protocol
#interface DepartmentViewController : UITableViewController
#property (nonatomic, weak) id <DepartmentViewControllerDelegate> delegate;
#end
#protocol DepartmentViewControllerDelegate
- (void)departmentViewController:(DepartmentViewController *)controller
isProcessingPeople:(NSArray *)people
#end
In your department view controller, you would then write something like this:
if ([self.delegate respondsToSelector:#selector(departmentViewController:isProcessingPeople:)]) {
[self.delegate departmentViewController:self isProcessingPeople:people];
}
And in your planning view controller, you would implement this method:
- (void)departmentViewController:(DepartmentViewController *)controller
isProcessingPeople:(NSArray *)people {
// do necessary work here
}
The example here is just an example of one message you can send to the delegate. You can add whatever you need, but this makes it so there is no coupling between your controllers. The planning view controller knows everything it needs to about the department controller, but the department controller doesn't need to know anything about the planning controller.
If you want to stick with what you have currently, just recognize that it's not really the delegate pattern, and you should probably rename your property.