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.
Related
I want to use Protocol Buffers in an iOS project. I'm trying to avoid making the whole project into an Objective-C++ fiasco, so I want to wrap the C++ protobuf classes into Objective-C ones. I have several dozen protobuf messages, and while I have done this successfully one class at a time, ideally I would like to use inheritance to minimize the repeated code. I'm new to Objective-C and I haven't used what little I knew of C++ in 10 years, so this has mostly been an exercise in frustration. Below is an example of how I have wrapped a single message.
Code
.proto:
message MessageA {
optional string value = 1;
}
MessageAWrapper.h:
#import <Foundation/Foundation.h>
#interface MessageAWrapper : NSObject
#property (nonatomic) NSString *value;
+ (id)fromString:(NSString *)string;
- (NSString *)serialize;
#end
MessageAWrapper.mm:
#import "MessageA.h"
#import "message.pb.h"
#interface MessageAWrapper ()
#property (nonatomic) MessageA *message;
#end
#implementation MessageAWrapper
- (id)init
{
self = [super init];
if (self) {
self.message = new MessageA();
}
return self;
}
- (void)dealloc {
delete self.message;
self.message = NULL;
}
- (NSString *)value {
return [NSString stringWithUTF8String:self.message->value().c_str()];
}
- (void)setValue:(NSString *)value {
self.message->set_value([value UTF8String]);
}
- (NSString *)serialize {
std::string output;
self.message->SerializeToString(&output);
return [NSString stringWithUTF8String:output.c_str()];
}
+ (id)fromString:(NSString *)string {
MessageA *message = new MessageA();
message->ParseFromString([string UTF8String]);
MessageAWrapper *wrapper = [[MessageAWrapper alloc] init];
wrapper.message = message;
return wrapper;
}
#end
Goal
There is a lot of code here that will be repeated dozens of times in which the only variation is the wrapped class type (init, dealloc, serialize, fromString), so ideally I would like to put it on a parent ProtobufMesssage class instead. Unfortunately I've had no success in making this work because I can't find a way for the parent class to know the class its children are using, which is required for example in init and fromString.
Things I've attempted
struct
template class
void*
Obstacles I've encountered
can't find a way to store a reference to a class/type
can't have any C++ headers or code in the .h file (as this requires the whole project to be Objective-C++)
difficulty keeping references to the protobuf message parents (Message or MessageLite) because they are abstract
As I said I have very little understanding of C++ or Objective-C; most of my experience is with much higher level languages like Python and Java (though I do mostly understand basic C things like pointers).
Is this perhaps not even possible? Am I approaching it wrong or missing something obvious? Any help would be much appreciated. Thanks.
I don't know much about C++ at all, but can't you declare the Objective-C property to be a Message *?
You've already separated the C++ code from the header by declaring the property in the .mm file, the problem you will have is with instance methods named by the compiler (value() and set_value()) and only being valid methods for the subclass. It might help to use the Reflection class to get and set fields by their name. Here is an excerpt from Google's message.h showing this:
Message* foo = new Foo;
const Descriptor* descriptor = foo->GetDescriptor();
const FieldDescriptor* text_field = descriptor->FindFieldByName("text");
assert(text_field != NULL);
assert(text_field->type() == FieldDescriptor::TYPE_STRING);
assert(text_field->label() == FieldDescriptor::LABEL_OPTIONAL);
const Reflection* reflection = foo->GetReflection();
assert(reflection->GetString(foo, text_field) == "Hello World!");
You could create Objective-C -objectForKey: and -setObject:forKey: instance methods that typecheck and get or set the value (confusingly, the key in the case of MessageAWrapper would be #"value"). Your subclasses would not even need to be aware of the C++ code.
You can also separate the creator function in -init and +fromString: method into something like, +_createNewInstance;
+(Message*)_createNewInstance{ return new MessageA(); }
allowing your subclasses of MessageWrapper to reuse all code except for creating the C++ object.
While Objective C has very powerful instrospection capabilities, C++ is more limited. You do have RTTI (Run time type information), but it's not even as powerful as the Objective C counterpart.
However, it might be enough for you. Within your Objective C++ class, you might find the type of you message object with the typeid operator:
if( (typeid(self.message) == typed(foo)){
//doSomething
else if( (typeid(self.message) == typed(bar)){
// doSomething else
}
Maybe the best option is to add another indirection level. Make an Objective C class hierarchy that wraps all your protocol buffer C++ classes and then create another Objective C that uses those classes (as delegates maybe). I believe this might be a better option. Use C++ only for those unavoidable cases.
Good luck!
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".
I'd like to write an Objective-C class without Cocoa or GNU's Object.h (for educational purposes). I dug around the net and it seems to me that quite a lot of stuff that one would expect to "come with the language", such as classes and message sending are actually defined in files written by third parties, such as objc-runtime.h.
Is there any documentation about what is really pure Objective-C and what is part of the runtime / frameworks? And what functionality do I have to implement to get a working environment without using any third-party code such as Object.h or objc-runtime.h (note again that this is for educational purposes, not for production code)?
Thanks for any insight!
Really, the only thing you must take care of yourself if you don't inherit from NSObject is object creation and destruction; methods otherwise behave the same way regardless of their parent class. Features like KVC and memory management are features of OpenStep/Cocoa, but not required as part of the language.
Here's a class from scratch:
#interface MyClass { // note the lack of a superclass here
#private Class isa;
}
+ (MyClass *)create;
- (void)destroy;
- (int)randomNumber;
#end
#implementation MyClass
+ (MyClass *)create {
return class_createInstance(self, 0);
}
- (void)destroy {
object_dispose(self);
}
- (int)randomNumber {
return rand();
}
#end
And here's how it could be used:
int main(int argc, char **argv) {
MyClass *foo = [MyClass create];
if (foo) {
printf("random! %i\n", [foo randomNumber]);
[foo destroy];
}
}
Edit: If you don't even want to use class_createInstance() and object_dispose(), you'll have to implement equivalents manually, as well as an equivalent of class_getInstanceSize() so you know how much memory an object occupies. But even if you manage that, don't think you've escaped the Objective-C runtime! Message dispatch is still entirely built on the C functions in the runtime, and Objective-C syntax is transformed into calls to those functions during compilation.
Matt Gallagher wrote a really cool post on writing a bare-bones Cocoa program. Since Objective-C is a superset of C, you can just do:
echo "int main(){return 0;}" | gcc -x objective-c -; ./a.out ; echo $?
Anyways, you probably would get a lot out of reading his post.
As far as avoiding the framework and creating your own base object goes, all you need to do is make sure that the first iVar is declared Class is_a and you could probably have a reasonable stab at replicating NSObject is by passing through to the runtime functions.
As far as avoiding the runtime library AND the framework goes, that's not really possible. Objective C (or at least, the bits that aren't just C) is a dynamic language. So pretty much everything it does that C doesn't do is handled by the runtime library.
It might be possible to build your own classes and objects using the 32bit runtime and the deprecated API, which doesn't abstract away the layout of classes, protocols, etc. to the extent that the modern runtime does (I've only really poked around with the modern runtime)
Perhaps you could create classes, add methods and allocate instances and by setting values in class_t structs and then using malloc() to allocate, although even then, you'd still be implicitly using the runtime function objc_msgSend every time you used the [obj selector] syntax -- unless you want to implement that as well, in which case you've just reimplemented the language yourself. The 'pure core' of the language you're looking for just is the runtime.
Here's an example of class, without using class_createInstance or object_dispose, or any other Objective-C Runtime (at least we don't call them directly).
#import <objc/objc.h>
#import <stdio.h>
#import <stdlib.h>
#import <string.h>
static Class __scratchClass = NULL;
#interface Scratch {
Class isa;
char *name;
}
+ (id) initialize;
+ (Scratch*) new:(const char*)strName;
- (void) sayHello;
- (void) destroy;
#end
#implementation Scratch
+ (id) initialize {
__scratchClass = self;
return self;
}
+ (Scratch*) new:(const char*) strName {
Scratch* pObj = (Scratch*)malloc(sizeof(Scratch));
if (!pObj) return NULL;
memset(pObj, 0, sizeof(Scratch));
pObj->isa = __scratchClass;
pObj->name = (char*)malloc(strlen(strName)+1);
strcpy(pObj->name, strName);
return pObj;
}
- (void) sayHello {
printf("Hello, World!\nThis is Scratch (%s)...\n", name);
}
- (void) destroy {
if (name) {
free(name);
name = NULL;
}
free(self);
}
#end
int main(int argc, char** argv) {
Scratch* ps = [Scratch new:argv[0]];
[ps sayHello];
[ps destroy];
return 0;
}
Compile the code with (assuming you save it as 'test1.m'):
gcc -o test1 test1.m -lobjc
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.
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.