iOS5, StoryBoards, ARC: Weird categories issue - objective-c

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.

Related

Accessing category method in original Objective C class

I have a class for which I have created a category. Now I want to access category method inside original class but I am getting error:
error: instance method '-hasSound' not found (return type
defaults to 'id') [-Werror,-Wobjc-method-access]
// Animal.h
#interface Animal: NSObject
- (void)sound;
#end
// Animal.m
#import "Animal+Additions.h"
#implementation Animal
- (void)sound {
[self hasSound];
}
#end
// Animal+Additions.h
#interface Animal (Additions)
- (BOOL)hasSound;
#end
// Animal+Additions.h
#implementation Animal (Additions)
- (BOOL) hasSound {
return YES;
}
#end
I have been doing same thing in Swift but not sure how to achieve the same thing in Objective C.
Category and original class are in separate files. I have imported Category interface file inside original class but that didn't work.
You have not shown sufficient #import statements, so I have to assume they don't exist. You need them.
Another possible issue is that, at least according to your comments, you seem to have two Animal+Additions.h files but no Animal+Additions.m file.
This complete code in four files compiles for me:
// Animal.h
#import <Foundation/Foundation.h>
#interface Animal: NSObject
- (void)sound;
#end
// Animal.m
#import "Animal.h"
#import "Animal+Additions.h"
#implementation Animal
- (void)sound {
[self hasSound];
}
#end
// Animal+Additions.h
#import "Animal.h"
#interface Animal (Additions)
- (BOOL)hasSound;
#end
// Animal+Additions.m
#import "Animal+Additions.h"
#implementation Animal (Additions)
- (BOOL) hasSound {
return YES;
}
#end
Note all the #import statements, and note that the Animal.m file must be part of the target.

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

Objective-C access another class

Objective-C newbie here.
I've been looking at this for way too long and decided to ask for help.
I have ViewController and TestClass. I want to message a method from TestClass called TestMethod in ViewController. Being from the C# world I would do:
TestClass testClass = new TestClass();
testClass.TestMethod();
I've searched for too long and haven't found a simple solution. All of the examples I've found either don't work or don't fit what I'm trying to do.
TestClass.h
#import <Foundation/Foundation.h>
#interface TestClass : NSObject
#end
TestClass.m
#import "TestClass.h"
#implementation TestClass
-(void)testMethod {
}
ViewController.h
#import "TestClass.h"
#interface ViewController : UIViewController
ViewController.m
#import "ViewController.h"
TestClass *testClass;
#interface ViewController()
#end
#implementation ViewController
-(void)viewDidLoad {
[testClass testMethod];
}
What am I missing?!?!
What you're missing is the equivalent of the line with new TestClass in it.
TestClass *testObject = [[TestClass alloc] init];
[testObject testMethod];
Also, put a declaration of your method into the TestClass.h interface.
-(void)testMethod;
And, it's a good idea to put...
#import "TestClass.h"
...into your ViewController.m file instead of your .h unless absolutely necessary.

Objective-C error "No visible #interface for 'XYZPerson' declares the selector 'saySomething'

I am really new to Objective-C and when I was practicing the book exercises, I really am stuck here. Please help me solve this and I have been thinking what could cause this error for more than three hours. Still I didn't get it!
Best regards,
Raj.
Thanks in advance !
main.m
#import <Foundation/Foundation.h>
#import "XYZPerson.h"
#import "XYZShout.h"
int main(int argc, const char * argv[])
{
#autoreleasepool {
//XYZPerson *some = [[XYZPerson alloc]init];
XYZShout *some = [[XYZShout alloc]init];
[some sayHello];
// insert code here...
// NSLog(#"Hello, World!");
}
return 0;
}
XYZPerson.h
#import <Foundation/Foundation.h>
#interface XYZPerson : NSObject
#property NSString *firstName;
#property NSString *secondName;
#property NSDate *dob;
-(void) saySomething;
-(void) sayHello;
#end
XYZPerson.m
#import "XYZPerson.h"
#implementation XYZPerson
-(void) sayHello {
[self saySomething:#"Hello all"];
}
-(void) saySomething:(NSString *)greet {
NSLog(#"%#", greet);
}
#end
XYZShout.h
#import "XYZPerson.h"
#interface XYZShout : XYZPerson
// -(void) saySomething;
#end
XYZShout.m
#import "XYZShout.h"
#implementation XYZShout
-(void) saySomething:(NSString *)greet {
NSString *upperGreet = [greet uppercaseString];
[super saySomething:upperGreet]; // this is where I get the error mentioned above
}
#end
Got it working ! Thanks to #MatthewD , #trojanfoe , #JFS for your big help :)
It looks like you are testing inheritance so I will assume that XYZShout is supposed to be derived from XYZPerson. If so follow the suggestion from #JFS and make sure it does actually derive:
XYZShout.h:
#import <Foundation/Foundation.h>
#import "XYZPerson.h"
#interface XYZShout : XYZPerson
- (void)saySomething:(NSString *)greet;
#end
And also correct the definition of saySomething in XYZPerson (you missed off the parameter):
XYZPerson.h:
#import <Foundation/Foundation.h>
#interface XYZPerson : NSObject
#property NSString *firstName;
#property NSString *secondName;
#property NSDate *dob;
- (void)saySomething:(NSString *)greet;
// ^^^^^^^^^^^^^^^^^
- (void)sayHello;
#end
(Moved from comments into an answer...)
MatthewD: What happens if you change - (void) saySomething; in XYZPerson.h to - (void) saySomething:greet;?
Raj0689: Why does it run when I change it to saySomething:greet and not saySomething ? Since greet is defined only along with saySomething !!
When you call a method, the compiler needs to locate the signature of that method so it can verify that the method is being called correctly. The signature includes the method name and the number and types of parameters. The usual way of providing method signatures is by importing the header file that defines those signatures.
So, in XYZShout.m where you call:
[super saySomething:upperGreet];
The compiler searches XYZShout.h, which is imported by XYZShout.m, and XYZPerson.h, which is imported by XYZShout.h. In XYZShout.h, the following method was being found:
-(void) saySomething;
This matches the called method in name, but not in parameters, so the compiler does not consider this a match. No other definitions of saySomething are found anywhere, so it gives an error instead.
Please make sure to set the XYZShout.h interface to #interface XYZShout : XYZPerson?

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.