In Objective-C, how to use 'self' in main() function? - objective-c

I have the definition:
#interface MyClass: NSObject
{
NSString *str;
id delegate;
}
-(id)initWithStr:(NSString *)str
delegate:(id)delegate;
#end
and when i send message to my object in the main.m like this:
int main(int argc, const char * argv[])
{
#autoreleasepool {
[[MyClass alloc] initWithStr:#"abc-xyz"
delegate:self];
}
}
There is the error "Use of undeclared identifier 'self' ". I m a newb of objective-c and I know that the 'self' indicates the receiver of the message, but i don't know how to use it in the main() function. Can anybody tell me what's wrong about it and how to fix it?

What happens is that self points to the executing object. main function is not in a class, so, YOU CAN`T call self on a function, only on a method of a class. What are you really trying to do? Use the AppDelegate. When you create a new project, Xcode already gives you some files. One of then is called (YOUR_PROJECT)AppDelegate. This is the starting point of your application.
If you have any customizations to do in the initialization of your app, find your AppDelegate.m file, look for - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions method, and place your code inside this method.
Never mess up with main.m file.
EDIT:
For Mac OS X here's what you should do:
Create a class to act as a delegate and add that class to the delegate.
MyDelegate * d;
MyClass * c;
int main(int argc, const char * argv[])
{
#autoreleasepool {
d = [[MyDelegate alloc] init];
c = [[MyClass alloc] initWithStr:#"abc-xyz"
delegate:d];
}
}
Then, on MyDelegate, implement the callbacks of the protocol.
If you want to have a callback on main, you will have to use a function pointer. You'll have to enter in the world of plain C. I don't recommend since you want to use object oriented stuff. Don't mix both, or you'll create a monster.

You do not use the main() function like this.
Do this in the AppDelegate, then it will just work.

In Objective-C, how to use 'self' in main() function?
This is impossible.
Because "self" can only be used by instances of objects.
main() is a function. Functions are not objects but code "on its own".

Related

Objective-C creating and accessing mutable array

I am trying to create an NSMutableArray to hold some objects but I m having real trouble understanding the proper syntax for creating one that all my methods in main.m can add to and access.
I have tried making it an #property in the interface of the object i want the array to store and i have also tried creating a custom init method that would initialise one, but outside of the method that creates the object and adds it to the array I am getting undeclared identifier errors on the array name.
I am more used to java where I can create the array that all methods can access but I understand that Objective-C would not allow this. Can someone give me a hand and give me an example of code to create an NSMutableArray that all my methods in main.m can access?
DISCLAIMER: The fact that you are writing code in main.m suggests that you've start a console app project in Xcode and aren't trying to write a Cocoa or Cocoa Touch app.
If you are trying to write a Cocoa or Cocoa Touch application for OS X or iOS, your main.m file should look about like this:
int main(int argc, char * argv[]) {
#autoreleasepool {
return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
}
}
And you should know what you're doing before you modify it (99.999% of the time, you'll never need to touch this file for a Cocoa/Cocoa Touch app).
So to restate, this answer assumes you're writing a simply console app to teach your self some Objective-C basics.
And if this assumption is incorrect, your question should be closed as unclear what you're asking.
Answer
Objective-C is a strict super-set of C. As such, anything we can do in C, we can also do in Objective-C. This includes declaring variables at the global scope. This is different from Java. In Java, everything is an object--everything resides in a class file. This includes the main method. Example:
public class MyApplication
{
public static Object[] myArray;
public static void main(String [] args)
{
// execution begins here
}
}
This is different from Objective-C. Not everything must reside in a class in Objective-C. If we want a global variable in Objective-C, we just declare it in the global scope. Example:
main.m
#import <Foundation/Foundation.h>
NSMutableArray * myArray;
int main(int argc, const char * argv[]) {
#autoreleasepool {
myArray = [NSMutableArray array];
}
return 0;
}
We can use myArray anywhere within main.m when we've declared it as such.
Let's note something here though... if it's not a member of a class, it's called a function, not a method. So we can declare C-style functions also in this global scope.
NSMutableArray * myArray;
void appendHelloWorld() {
[myArray addObject:#"Hello World"];
}
NSInteger myArrayCount() {
return myArray.count;
}
int main(int argc, const char * argv[]) {
#autoreleasepool {
myArray = [NSMutableArray array];
while (myArrayCount() < 10) {
appendHelloWorld();
}
NSLog(#"%#", myArray);
}
return 0;
}
This all works perfectly fine. If we run this program, we'll get the following output:
2015-05-01 13:22:21.188 ObjC[18340:4210463] (
"Hello World",
"Hello World",
"Hello World",
"Hello World",
"Hello World",
"Hello World",
"Hello World",
"Hello World",
"Hello World",
"Hello World"
)
But... this isn't the right way...
I've merely demonstrated to you exactly how to do exactly what your asking for, but we really don't want to get into doing things this way. This is the path to using globals as the answer to everything. This is the path to using singletons as the answer to everything. This is the path to writing applications that have 12 different singleton classes (I've seen it). This isn't the path to Sparta--this is the path to madness.
Instead, we should be dealing with instances of objects.
Our functions (or when we graduate to classes, our methods) should be passed an argument, and we shouldn't have a variable in the global scope.
So, let's get rid of the global variable and amend our methods:
void appendHelloWorld(NSMutableArray *array) {
[array addObject:#"Hello World"];
}
NSInteger arrayCount(NSArray *array) {
return array.count;
}
int main(int argc, const char * argv[]) {
#autoreleasepool {
NSMutableArray *myArray = [NSMutableArray array];
while (arrayCount(myArray) < 10) {
appendHelloWorld(myArray);
}
NSLog(#"%#", myArray);
}
return 0;
}
Running this program gives us identical output:
2015-05-01 13:27:48.594 ObjC[18361:4213356] (
"Hello World",
"Hello World",
"Hello World",
"Hello World",
"Hello World",
"Hello World",
"Hello World",
"Hello World",
"Hello World",
"Hello World"
)
It also makes our code more flexible. Our function, appendHelloWorld isn't so tightly coupled to this code-based. It can be plunked out of this and into anywhere else and perform exactly as expected. It's not coupled to anything. It will drop the string, #"Hello World", onto any mutable array it is passed. And while arrayCount() is really unnecessary (just using it as an example), we can say all of the same things for it.
We don't want to use global variables and we don't want functions or methods so tightly coupled to global variables. We need to get comfortable with the idea of instantiating instances of objects and passing these objects to the methods or functions that need them.
Singletons should be used not when it is important for multiple classes to access some shared memory store--NO--that's not what singletons are for. Singletons should be used when you need to be certain only one instance of the class is instantiated ever in the life time of the app.
Not that I really understand why you would want to have a lot of functions in main.m. One way to achieve what you say you want to do, but probably don't want to do, is to create a class with a static instance
#interface GlobalArrayHolder
#property (nonatomic, readonly) NSMutableArray *globalArray;
+ (instancetype)sharedGlobalArrayHolder;
#end
With an implementation something like
#implementation GlobalArrayHolder
#synthesize globalArray = _globalArray
- (instancetype) init {
self = [super init];
if (self) {
_globalArray = [NSMutableArray arrayWithCapacity:5];
}
return self;
}
+ (instancetype) sharedGlobalArrayHolder {
static GlobalArrayHolder *localGlobalArrayHolder = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
localGlobalArrayHolder = [[GlobalArrayHolder alloc] init];
});
return localGlobalArrayHolder;
}
#end
You want to read up about how an iOS or OS X app actually works and learn about the app delegate. Adding a lot of functions to main.m sounds like a really bad idea.
If #nhgrif is correct and you only want to start playing around with Objective-C you could declare the array as static in the file scope of main.m
#import <Foundation/Foundation.h>
static NSMutableArray *globalArray = nil;
int main(int argc, const char *argv[])
{
globalArray = [NSMutableArray arrayWithCapacity:5];
return 0;
}
Please note that this definitely not the way to go about writing a iOS or OS X app. The only thing main should do is to call UIApplicationMain or NSApplicationMain, probably inside #autoreleasepool { }. The XXApplicationMain method then goes about setting things up before calling out to the app delegate where you start implementing the real work.
To compile with clang from the command line: clang main.m -framework Foundation
I think this is a beginners question. However, MutableArrays can sometime be tricky.
First thing to mention is: NSMutableArrays are NOT thread safe. Keep this in mind if you store them as a property.
If you want something which is accessible from ALL methods, you have a lot of choices. This depends on your desired software architecture.
The most simple thing for global accessible data is NSUserDefaults (for values like preferences, which are stored not very frequently).
If you need to work on that data, you can simply create a so called singleton. A singleton is a class-instance which exists only once. This class would behave like your java example. If you access that class all values are everywhere the same. In general it's not a good advice to use java style development with objC. There is always another option to write good code. To transmit data from an class to another you could use NSNotifications. Another good thing is using delegates (search for delegates and #protocol).
In your special case the following code should work. We call it a singleton. It's a class which has only one instance and is accessible from everywhere:
.h file:
#import <Foundation/Foundation.h>
#interface MySingletonClass : NSObject
#property(nonatomic, strong) NSMutableArray *list;
+(MySingletonClass*) sharedInstance;
#end
.m file:
#import "MySingletonClass.h"
#implementation MySingletonClass
+(MySingletonClass*) sharedInstance {
static MySingletonClass* theInstance = nil;
if (!theInstance) {
theInstance = [[MySingletonClass alloc] init];
// The following line initializes an empty array
theInstance.list = [NSMutableArray array];
}
return theInstance;
}
#end
Now you can import this class everywhere
#import "MySingletonClass.h"
And use it like this:
[[MySingletonClass sharedInstance].list addObject:#"Example object"];
If you are used to 'java' yo maybe switch over to swift. The syntax is more similar to java.

Trouble with calling a method in Objective C (Apple Documentation example)

I'm following along with Apple's "Programming with Objective C" document, the link being: https://developer.apple.com/library/ios/documentation/Cocoa/Conceptual/ProgrammingWithObjectiveC/WorkingwithObjects/WorkingwithObjects.html#//apple_ref/doc/uid/TP40011210-CH4-SW1
Anyways, I've gotten to the point where it ask for calling the sayHello method.
"Create a new XYZPerson instance using alloc and init, and then call the sayHello method."
#import <Foundation/Foundation.h>
#import "XYZPerson.h"
int main(int argc, const char * argv[]);
XYZPerson *firstPerson = [[XYZPerson alloc] init]; //Initializer element is not a lime-time constant
[firstPerson sayHello]; //No Visible #interface for 'XYZPerson' delcares the selector 'sayHello'
#implementation XYZPerson
- (void)sayHello {
[self saySomething:#"Hello, World"];
}
- (void)saySomething: (NSString *)greeting {
NSLog(#"%#", greeting);
}
#end
I believe I'm having a misunderstanding with how apple is explaining the work or just have no clue.
Wishing apple had these examples done for us to review over.
You need to put the code inside the main function. Right now you have the code just sitting in your file, outside of any function. It should be:
int main(int argc, const char * argv[]) {
XYZPerson *firstPerson = [[XYZPerson alloc] init];
[firstPerson sayHello];
}
Also, according to the docs you should have a separate main.m file that has your main function inside of it.
As you can only access public functions which are declared in .h file with the class object.
Kindly declare that function in .h file and it will solve your problem

How to call an Objective-C Method from a C Method?

I have an Obj-C object with a bunch of methods inside of it. Sometimes a method needs to call another method inside the same object. I can't seem to figure out how to get a C method to call a Obj-C method...
WORKS: Obj-C method calling an Obj-C method:
[self objCMethod];
WORKS: Obj-C method calling a C method:
cMethod();
DOESN'T WORK: C method calling an Obj-C method:
[self objCMethod]; // <--- this does not work
The last example causes the compiler spits out this error:
error: 'self' undeclared (first use in this function)
Two questions. Why can't the C function see the "self" variable even though it's inside of the "self" object, and how do I call it without causing the error? Much thanks for any help! :)
In order for that to work, you should define the C method like this:
void cMethod(id param);
and when you call it, call it like this:
cMethod(self);
then, you would be able to write:
[param objcMethod];
In your cMethod.
This is because the self variable is a special parameter passed to Objective-C methods automatically. Since C methods don't enjoy this privilege, if you want to use self you have to send it yourself.
See more in the Method Implementation section of the programming guide.
I know your question is already answered by Aviad but just to add to the info since this is not unrelated:
In my case I needed to call an Objective-C method from a C function that I did not call myself (a Carbon Event function triggered by registering a global hotkey event) so passing self as a parameter was impossible. In this particular case you can do this:
Define a class variable in your implementation:
id thisClass;
Then in your init method, set it to self:
thisClass = self;
You can then call Objective-C methods from any C function in the class without the need to pass self as a parameter to the function:
void cMethod([some parameters]) {
[thisClass thisIsAnObjCMethod];
}
C function is not "inside of the self object". In fact, nothing is.
Objective-C methods effectively get self as an implicit argument, with magic done under the hood. For plain C functions, they aren't associated with any class or object, and there's no call magic, so no self. If you need it, you need to pass it to your C function explicitly as an argument.
To be totally truthful, there is no such thing as a C method. C has functions. To illustrate the difference, look at the following examples:
This is a working C program that defines a type and two functions that go along with it:
#include <stdio.h>
typedef struct foo_t {
int age;
char *name;
} Foo;
void multiply_age_by_factor(int factor, Foo *f) {
f->age = f->age * factor;
}
void print_foo_description(Foo f) {
printf("age: %i, name: %s\n", f.age, f.name);
}
int main() {
Foo jon;
jon.age = 17;
jon.name = "Jon Sterling";
print_foo_description(jon);
multiply_age_by_factor(2, &jon);
print_foo_description(jon);
return 0;
}
Here is an Objective-C implementation of that program:
#import <Foundation/Foundation.h>
#interface Foo : NSObject {
NSUInteger age;
NSString *name;
}
#property (nonatomic, readwrite) NSUInteger age;
#property (nonatomic, copy) NSString *name;
- (void)multiplyAgeByFactor:(NSUInteger)factor;
- (NSString *)description;
- (void)logDescription;
#end
#implementation Foo
#synthesize age;
#synthesize name;
- (void)multiplyAgeByFactor:(NSUInteger)factor {
[self setAge:([self age] * factor)];
}
- (NSString *)description {
return [NSString stringWithFormat:#"age: %i, name: %#\n", [self age], [self name]];
}
- (void)logDescription {
NSLog(#"%#",[self description]);
}
#end
int main (int argc, const char * argv[]) {
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
Foo *jon = [[[Foo alloc] init] autorelease];
[jon setAge:17];
[jon setName:#"Jon Sterling"];
[jon logDescription];
[jon multiplyAgeByFactor:2];
[jon logDescription];
[pool drain];
return 0;
}
The output of the pure C program was:
age: 17, name: Jon Sterling
age: 34, name: Jon Sterling
The output of the Objective-C program was:
2009-08-25 17:40:52.818 test[8963:613] age: 17, name: Jon Sterling
2009-08-25 17:40:52.828 test[8963:613] age: 34, name: Jon Sterling
The only difference is all the junk that NSLog puts before the text. The functionality is exactly the same. So, in C, you can use something sort of like methods, but they are really just functions that include a pointer to a struct.
I don't think this answered your original question, but it did clear up some terminology issues you appear to have been having.
Another option to the answers given thus far is to use the objc_msgSend() function provided by the Objective-C runtime.

Handling class methods when sub-classing in objective-c

While attempting my first sub-class in Objective-C I have come across the following warning which I cannot seem to resolve. The call to decimalNumberWithMantissa gives a warning of "initialization from distinct Objective-C type".
#import <Foundation/Foundation.h>
#interface NSDecimalNumberSub : NSDecimalNumber {
}
#end
#implementation NSDecimalNumberSub
#end
int main (int argc, char *argv[]) {
NSDecimalNumberSub *ten = [NSDecimalNumberSub
decimalNumberWithMantissa:10
exponent:0
isNegative:NO];
}
Does a class method have to be treated differently with a sub-class? Am I missing something simple? Any help would be appreciated.
NSDecimalNumber defines the decimalNumberWithMantissa:... method to return an NSDecimalNumber, so you're going to get back an instance of the base class and not your custom subclass. You'll have to create your own convenience method to return an instance of your subclass, or just alloc and initialize it another way.
If you're writing your own class you can define a convenience method like that to return type id, and then use [[self alloc] init] when creating the instance to make your class safe for subclassing.

Objective-C equivalent to Ruby's #define_method?

Is it possible to dynamically define methods in Objective-C like we would in Ruby?
[:failure, :error, :success].each do |method|
define_method method do
self.state = method
end
end
Actually it is possible to do this, although it's not supported by the obj-c syntax, the obj-c runtime provides functions that can do it. The one you want is class_addMethod, but off the top of my head i cannot remember the exact specifics of how. All the runtime methods are documented at developer.apple.com
For the hell of it I banged up a very simple example
#import <objc/objc-class.h>
#interface MyClass : NSObject {
}
#end
#implementation MyClass
#end
id myMethod(id self, SEL cmd, NSString* message)
{
NSLog(message);
return nil;
}
int main(int argc, char *argv[])
{
class_addMethod([MyClass class], #selector(newMethod:), (IMP)myMethod, "v#:#");
[[[MyClass alloc] init] newMethod:#"Hello World"];
return 0;
}
Now strictly speaking i think myMethod should be varargs, and it just happens to be okay to do it the way i am on x86, and may fail on ppc -- but then i could be wrong.
Oh here's the awful type encoding docs
I don't beleive it's possible, because Objective C is, after all, a compiled language. Your "define method" which have to add methods to the table and have a way to compile the method at run time.