I created a preprocessor definition to allocate and construct classes for me as follows:
#define new(cls) cls* _new() {return [[cls alloc] init];}()
Now I tried using it like:
- (NSMutableArray*) stack
{
if (!_stack)
{
/*_stack = [[NSMutableArray alloc] init];*/
_stack = new(NSMutableArray);
}
return _stack;
}
but it says expected expression and unexpected NSMutableArray interface. What is wrong with my definition and why can't I do it? Is there another way I can do this?
Just use new:
_stack = [NSMutableArray new];
which does the same thing as
_stack = [[NSMutableArray alloc] init];
No need for a macro which will be confusing to others.
For a long time the use of new was discouraged by Apple but it seems with the arrival of ARC it has come back into favor even in Apple's documentation.
Related
I'm beginner ObectiveC user so please keep potential answers simple.
I have quite a few years experience with C and C++.
Now, with ObjectiveC I want to create two objects, not using properties. My question is "what is wrong here" not "how to do it differently".
So there is my code:
#implementation News
NSString *_title;
NSString *_excerpt;
NSString *_content;
NSString *_thumbnailURL;
NSString *_date;
-(id)initWithTitle:(NSString *)title excerpt:(NSString *)excerpt content:(NSString*)content thumbnail:(NSString *)thumbnailURL date:(NSString *)date {
self = [super init];
if (self) {
_title = [[NSString alloc] initWithString:title];
_excerpt = [[NSString alloc] initWithString:excerpt];
_content = [[NSString alloc] initWithString:content];
_thumbnailURL = [[NSString alloc] initWithString:thumbnailURL];
_date = [[NSString alloc] initWithString:date];
}
return self;
}
-(void)showData {
NSLog(#" title:%#", _title);
NSLog(#" excerpt:%#", _excerpt);
NSLog(#" thumbnailURL:%#", _thumbnailURL);
NSLog(#" date:%#", _date);
NSLog(#" getContent:%#", _content);
}
#end
Now I want to create two objects:
News *nws = [[News alloc] initWithTitle:#"title1" excerpt:#"excerpt1" content:#"content1" thumbnail:#"thumbnail1" date:#"date1"];
News *nws2 = [[News alloc] initWithTitle:#"title3" excerpt:#"excerpt3" content:#"content3" thumbnail:#"thumbnail3" date:#"date3"];
After that want to show whats is inside this objects:
[nws showData];
[nws2 showData];
Result is that both objects have the same values inside. All ended with "3". I thought that nws object will containt values ending with "1" and nws2 will contain values with "3". But it isnt working like that. Why? Where is an error?
Please help and thanks!
I asked in twitter and got the following comment from #Bavarious:
https://gist.github.com/11c22c0edea5391a3799 (bold added)
Any variable declared outside of #interface … {} or #implementation … {} is treated as a regular C variable.
In your example, _excerpt
is a global (file scope) variable with static storage duration and
could equivalently be placed at the top of the file before
#interface, or between #interface and #implementation, or
between the implementation of two methods — it’s the same mechanism
where file scope variables in C are defined outside of a function
block.
Variables with static storage duration can be used to realise class
variables, a concept that doesn’t exist in Objective-C.
Your variables are defined as global variables (and not instance variables), this why they have the same same value referenced from your instances.
Embedding them in {} is a possible solution in your case.
I have a marshmallow class which has (among other things) a CCSprite object as an instance variable.
here is the init method:
-(id) init
{
if((self = [super init]))
{
model = [[CCSprite spriteWithFile:#"marshmallow.png"] retain];
maxSpeed = 5; //160px per second (maxspeed * PTM_Ratio = px/second max)
gravity = 9.81; // in meters/sec^2
health = 3;
}
return self;
}
the variable is declared in another file as a global variable with the line:
Marshmallow *mainChar;
Later in the file, it is set (initiated/alloc'd) with this line:
mainChar = [[mainChar alloc] init];
while writing the previous line, xcode gave me a warning that Marshmallow might not respond to alloc. (I don't think that's related. just mentioning anything that seems wrong)
my problem is that the following line of code returns nil:
[mainChar getModel];
why does it return nil instead of the instance variable?
here is the getModel function:
-(CCSprite *)getModel
{
return model;
}
mainChar = [[mainChar alloc] init];
Shouldn't be
mainChar = [[Marshmallow alloc] init];
?
The message says an object from that class might not respond to it, not the class itself.
Your problem is in the initialization of your mainChar variable. The line you're looking for is this:
mainChar = [[mainChar alloc] init];
The warning you got is telling you that instances of type Marshmallow will not respond to the -alloc message. That is your problem: you want to call the +alloc class method instead, like so:
mainChar = [[Marshmallow alloc] init];
I think you want to do
mainChar = [[MarshMallow alloc] init];
instead of
mainChar = [[mainChar alloc] init];
The error message you got is very important.
I have a class like this:
#interface MyCollection : NSObject {
NSMutableDictionary *data;
}
and in the implementation of it, I have a method to init it like this:
- (id) init {
if(self = [super init])
{
self.data = [[NSMutableDictionary alloc] init];
}
return self;
}
Now when I create a object of this class in my code like this:
MyCollection *c = [[MyCollection alloc] init];
... at which point the Leaks utility shows that I have a memory leak in the init function on the very line where I try to set up the instance variable. I am totally new to Objective C & Iphone and I can't just get what is going wrong here. I have read through the Memory Management Guide and all, but I think I'm missing something pretty serious here.
Any help would be greatly appreciated. Thanks for your time already.
you are using self.data =. So there is most likely a property. And it most likely is a property which either copies or retains your object if you use it.
By calling
self.data = [[NSMutableDictionary alloc] init];
The retain count of the NSMutableDictionary increases because of the alloc, and if the property of data has a retain or copy statement you get another increase in retain count.
you could write data = [[NSMutableDictionary alloc] init]; or self.data = [NSMutableDictionary dictionary]. This would increase the retain count only one time.
And don't forget to release the object in dealloc.
You have to release the object in your dealloc method. That's why it's showing up as a leak.
to add to what fluchtpunkt mentioned you could try this instead:
- (id) init {
if(self = [super init])
{
self.data = [NSMutableDictionary dictionaryWithCapacity:0];
}
return self;
}
and in the dealloc
-(void)dealloc
{
self.data = nil;
}
I see weird situations with the Leaks utility as sometimes it reports old leaks, sometimes it doesn't report new ones, and so on. Also, from what I could collect with all your answers and opinion elsewhere on the web, people are divided on whether one should set a pointer to nil or not.
As of now, I have solved the situation with the following approach.
- (id) init {
if(self = [super init])
{
data = [[[NSMutableDictionary alloc] initWithCapacity:0];
}
return self;
}
-(void)dealloc
{
[data release];
}
Thanks everyone for contributing.
Are you creating the instance of "MyCollection" in the interface section?
If it has method scope try to release it in the same method after you are done with it.
This is probably a completely stupid question, but i'm pretty new at objective-C and programing in general.
i'm trying to make an array of arrays but can't manage to make it work :
#interface ArraysAndDicts : NSObject {
NSMutableArray * mySimpleArray;
NSMutableArray * myComplicatedArray;
}
the implementation :
-(void)generateValueForArrayOfArrays {
[self generateValueForArray];
//this generates an array with 5 elements 'mySimpleArray'
[myComplicatedArray addObject:mySimpleArray];
NSMutableArray * mySecondaryArray = [[NSMutableArray alloc] init];
[mySecondaryArray addObject:#"twoone"];
[mySecondaryArray addObject:#"twotwo"];
[myComplicatedArray addObject:mySecondaryArray];
(i edited out all the NSLogs for clarity)
When running my app, the console tells me :
mySecondaryArray count = 2
mySimpleArray count = 5
myComplicatedArraycount = 0
So, i know there are other ways to make multidimensional arrays,
but i'd really like to know why this doesn't work.
Thank you.
It looks like you're never creating myComplicatedArray. This means that
[myComplicatedArray addObject:mySimpleArray];
is actually
[nil addObject:mySimpleArray];
Sending messages to nil simply has no effect in Objective-C, so nothing happens. When you ask for the count of the array, you're effectively sending [nil count], which will return 0 in your case. You can find more information about sending messages to nil here.
Also, when you're doing
NSMutableArray * mySecondaryArray = [[NSMutableArray alloc] init];
[mySecondaryArray addObject:#"twoone"];
[mySecondaryArray addObject:#"twotwo"];
mySecondaryArray will leak. You should release it, either with autorelease
NSMutableArray * mySecondaryArray = [[[NSMutableArray alloc] init] autorelease];
...
or release, whichever is appropriate.
NSMutableArray * mySecondaryArray = [[NSMutableArray alloc] init];
...
[mySecondaryArray release];
We can't see how myComplicatedArray is initialised. Perhaps it's nil.
Did you initialize myComplicatedArray somewhere?
myComplicatedArray = [[NSMutableArray alloc] init];
[self generateValueForArray];
// etc...
I am new to Objective-C, but I tried to use HOM (higher order message) in order to iterate over an NSArray and append a string to each element.
Here is my code:
void print( NSArray *array ) {
NSEnumerator *enumerator = [array objectEnumerator];
id obj;
while ( nil!=(obj = [enumerator nextObject]) ) {
printf( "%s\n", [[obj description] cString] );
}
}
int main( int argc, const char *argv[] ) {
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
NSArray *names = [[NSArray alloc] init];
NSArray *names_concat = [[NSArray alloc] init];
names = [NSArray arrayWithObjects:#"John",#"Mary",#"Bob",nil];
names_concat = [[names collect] stringByAppendingString: #" Doe"];
print(names_concat);
[pool release];
}
What is wrong with this code?
My compiler (gcc) says NSArray may not respond to "-collect"
Because the method -collect is not part of the standard Objective-C library!
You need to get some library and add it to your project to start with. See an article at CocoaDev. For collect, see this blog article.
Starting from 10.6, Apple added some methods to NSArray which accepts blocks (or in other words closures). See NSArray documentation and look for words block.
By the way, on a rather unrelated point, please don't use the method cString. This is deprecated! See NSString documentation. cString is very bad concerning the encoding of the characters. I know you're only using it for a debug purposes, but I don't want you to make it a habit to use deprecated methods in general, and especially about methods concerning encodings.
OS X is in general a OS very friendly to many encodings, but as an East Asian I saw many great programs behaving badly just because the programmers used cString etc... Everything works as long as you use non-deprecated methods. Sorry for putting an unrelated comment :p