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.
Related
I have some objective-C code with a few classes. I'm trying to initialize each of the first two classes within the third class. One works fine, turns the right color in Xcode and allows me to jump to the definition. The other for some reason doesn't. I've poured over it but can't see what distinguishes the two.
MainClass.m:
#import "Class1.h"
#import "Class2.h"
#implementation MainClass
Class1 *class1 = [Class1 new];
Class2 *class2 = [Class2 new];
#end
Class1.h:
#ifndef Class1_h
#define Class1_h
#interface Class1 : NSObject
#end
#endif
Class2.h:
#ifndef Class2_h
#define Class2_h
#interface Class2 : NSObject
#end
#endif
There's no difference in header files of Class1.h and Class2.h. Both are imported into the MainClass.m But for some reason Class2 isn't recognized in MainClass.m, yields "Initializer element is not a compile-time constant" on Build+Run and doesn't allow me to command-click and jump to the definition.
I'm not sure where to look at this point. I've copied and pasted the code from the Class1.m file into Class2.m only changing the #import Class2.h header import and #implementation Class2 lines to make sure its not something in the .m files...problem persists.
You have an apostrophe instead of a double-quote at the end of your second import.
You might have a lingering #define of Class2_h somewhere. (This can happen if you use this #ifndef/#define/#endif pattern, especially if cutting and pasting code.)
For what it’s worth, you really don't need this #ifndef/#define/#endif pattern around your #interface references. Often C programmers are used to using this pattern a lot, but it’s just not needed in Objective-C class definitions.
For example, consider scenario where Class1 had a property that was a Class2:
// Class1.h
#import "Foundation/Foundation.h"
#import "Class2.h"
#interface Class1 : NSObject
#property (nonatomic, strong) Class2 *class2;
#end
And
// Class2.h
#import "Foundation/Foundation.h"
#interface Class2 : NSObject
#end
Then MainClass can import both headers without incident (even though Class1.h currently imports Class2.h already):
// MainClass.m
#import "MainClass.h"
#import "Class1.h"
#import "Class2.h"
#implementation MainClass
- (void)foo {
Class1 *class1 = [Class1 new];
Class2 *class2 = [Class2 new];
NSLog(#"Class1: %#", class1);
NSLog(#"Class2: %#", class2);
}
#end
You would have thought that this redundant #import "Class2.h" would cause problems, but it doesn’t. Objective-C tried to get us out of worrying about all of these #define references.
Now, that having been said, using that above example, Class1.h might not even #import the Class2.h file, at all, but it might just do a forward declaration of the class. And if Class1 implementation needed to interact with Class2 objects, you’d do the #import of Class2.h in Class1.m, not Class1.h:
// Class1.h
#import "Foundation/Foundation.h"
#class Class2;
#interface Class1 : NSObject
#property (nonatomic, strong) Class2 *class2;
#end
But regardless, we just don't tend to use the #ifndef/#define/#endif pattern in Objective-C.
Take this simple class hierarchy:
Tree.h:
#interface Tree : NSObject
#property (nonatomic, assign) id<TreeDelegate> delegate;
#end
Tree.m:
#implementation Tree
#synthesize delegate;
#end
Aspen.h:
#interface Aspen : Tree
- (void)grow:(id<TreeDelegate>)delegate;
#end
Aspen.m:
#implementation Aspen
- (void) grow:(id<TreeDelegate>)d {
self.delegate = d;
}
#end
When I try to do self.delegate = d;, I'm getting the following error:
-[Aspen setDelegate:]: unrecognized selector sent to instance 0x586da00
I was expecting the Tree parent class's delegate property to be visible to the subclass as-is, but it doesn't seem to be since the error indicates the parent class's synthesized setter isn't visible.
What am I missing? Do I have to redeclare the property at the subclass level? I tried adding #dynamic at the top of the implementation of Aspen but that didn't work either. Such a simple concept here, but I've lost an hour searching around trying to find a solution. Out of ideas at this point.
--EDIT--
The above code is just a very stripped-down example to demonstrate the issue I'm seeing.
I just tried your code, supplemented by the protocol, an object implementing it, the necessary import and a main function and on my system it works like a charm:
#import <Foundation/Foundation.h>
#protocol TreeDelegate <NSObject>
#end
#interface MyDelegate : NSObject <TreeDelegate>
#end
#implementation MyDelegate
#end
#interface Tree : NSObject
#property (nonatomic, assign) id<TreeDelegate> delegate;
#end
#interface Aspen : Tree
- (void)grow:(id<TreeDelegate>)delegate;
#end
#implementation Tree
#synthesize delegate;
#end
#implementation Aspen
- (void) grow:(id<TreeDelegate>)d {
self.delegate = d;
}
#end
int main(int argc, char ** argv) {
MyDelegate * d = [[MyDelegate alloc] init];
Aspen * a = [[Aspen alloc] init];
[a grow:d];
return 0;
}
I was finally able to figure this out. My actual code leverages a 3rd party static library that defines the classes Tree and Aspen in my example. I had built a new version of the static library that exposed the Tree delegate given in my example, however I did not properly re-link the library after adding it to my project and as a result the old version was still being accessed at runtime.
Lessons learned: be diligent with steps to import a 3rd party library, and when simple fundamental programming concepts (such as in my example text) aren't working, take a step back and make sure you've dotted i's and crossed t's.
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.
In a first controller, I create an instance variable for my model, because I want to edit its content from a controller and then access the same object from another controller.
In the second controller, I get an error when trying to access the object:
Property 'levels' not found on object of type FirstController.
Model.h
#imports....
#property (readwrite,copy) NSMutableString *answersString;
FirstController.h
#import <UIKit/UIKit.h>
#import "Model.h"
#interface FirstController : UIViewController{
// some declarations
}
#property (nonatomic, retain) LevelsCompleted *levels;
#end
FirstController.m
#import "FirstController.h"
#interface FirstController(){
//stuff
}
#end
#implementation FirstController
#synthesize levels;
//stuff
- (IBAction)backButton:(id)sender { // This is the changeAnswerString method
if (levels ==nil) self.levels = [[LevelsCompleted alloc]init];
self.levels.answersString=#"1";
[self dismissModalViewControllerAnimated:NO];
}
#end
SecondController.m
#import "SecondController.h"
#import "FirstController.h"
#interface SecondController(){
//stuff
}
#end
#implementation SecondController
-(void) viewWillAppear:(BOOL)animated{
NSLog(#"%#",FirstController.levels.answersString);
// the line above gives me the error "Property 'levels' not found on object of type FirstController
}
#end
Can someone tell me what I am doing wrong here? I have tried to create a FirstController object in the SecondController.h, but this does not give me the same property and hence I do not get the right value of the NSString I modified in the first view.
levels is a instance variable so you cannot access it without instantiating an object first.
You should do something like
FirstController *controller = [[FirstController alloc] initWithNibName:#"First" bundle:nil];
NSLog(#"%#",controller.levels.answersString);
[controller release]
You cannot access another viewcontroller from current viewcontroller directly. Define Level in AppDelagte method and then you can access it from anywhere.
What about moving/adding the LevelsCompleted *levels property to the secondviewcontroller and fill SecondViewcontroller.levels.answerstring when you use backbutton: in you first controller?
As a advice try NSUSERDEFAULT to access it,.,
By Doing Things As Below you can Achive as You want
Ddeclare NSMutableString As in your viewController Class As Global variable.
1) LevelsCompleted.h Class
#import <UIKit/UIKit.h>
NSMutableString *answersString;// In this way this answersString would accessible through out the Application and No Need to make property & synthesiz answersString .
#interface LevelsCompleted : UIViewController{
}
LevelsCompleted.m Class
//First create that NSMutableString object in its LevelsCompleted.m class
#import"LevelsCompleted.h"
#interface LevelsCompleted
-(void)viewDidLoad{
answersString=[NSMutableString alloc]init];//here created answersString object
}
#end //end of LevelsCompleted
2)FirstController.h class
#import <UIKit/UIKit.h>
extern NSMutableString *answersString;
#interface FirstController : UIViewController{
// some declarations
}
#end
FirstController.m class
#import "FirstController.h"
#implementation FirstController
- (IBAction)backButton:(id)sender {
// Because i have created that answersString Global in LevelsCompleted.h class
//we can directly Access and can set the any string Value to that answersString as Below
answersString=#"1";
[self dismissModalViewControllerAnimated:NO];
}
#end
SecondController.h class
extern NSMutableString *answersString;// please do this carefully fro getting access the answersString instance
#interface SecondController:UIViewController{
//stuff
}
#end
SecondController.m class
#implementation SecondController
-(void) viewWillAppear:(BOOL)animated{
NSLog(#"%#",answersString);//here you may access easily.
}
#end
In above code everything would work because i have done the same thing in my app
just try to catch the concept of extern, global variable .
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.