if header file declares
#interface SomeClass: NSObject {
Data* d;
}
#property (nonatomic, retain) Data* d;
Why is the following line in the implementation file giving me a warning (and init method does not get called?)
[[[self d] alloc] init];
The warning i get is
Instance method '-alloc' not found (return type defaults to 'id')
Meanwhile, Data has
- (id) init method, that is not being called.
Please help me understand why.
alloc should be invoked on a class, not on an instance.
interface SomeClass : NSObject
{
Data *d;
}
Declare an init method on SomeClass and make it look like:
- (id) init
{
self = [super init];
if (self)
{
d = [[Data alloc] init];
}
return self;
}
- (void) dealloc
{
[d release];
[super dealloc];
}
Now you do:
SomeClass *c = [[SomeClass init] alloc];
And you can use the class. Note that you should probably read a little more on classes and objects and about memory management too (when you should release c, etc.).
If, by any chance, you have the possibility to use ARC (automatic reference counting), you won't need to take care of releasing stuff. But that doesn't come with Xcode 4.1, only with 4.2 which is not publicly accessible, apparently.
The problem isn't -(id)init, it's -(id)alloc. alloc is a class method of NSObject, which means you send it to the class itself and not to an instance of that class, i.e.:
[Data alloc]; // Correct
[someDataInstance alloc]; // Method not found
When you call [self d], you're given an instance of a Data, which you're then sending a -(id)alloc message to. Since NSObject doesn't have a -(id)alloc (only a +(id)alloc), you get the warning.
You should be doing
self.d = [[Data alloc] init];
As Matt says, alloc is a class method, and must be called on the class itself.
Related
In the code below, when I run it with the GCC_OPTIMIZATION_LEVEL set to None, execution works as I expect and it prints the following to the console:
My Obj - SomeObj
However, when I set the GCC_OPTIMIZATION_LEVEL to Fastest, Smallest in the Xcode target configuration (as one typically does for Release builds) I end up with the following printed to the console:
My obj - (null)
The object appears to be getting released when I store it into the __weak id myObj variable in [Foo doSomething]. If I remove the __weak flag from the myObj variable the code runs as expected when the GCC_OPTIMIZATION_LEVEL is set to Fastest, Smallest.
I built this example based on a similar pattern I had in another project and added the __weak flag because I was encountering a retain cycle. The retain cycle warning went away, but when I built for Release, I found that myObj would be nil by the time it got to the spot where I am logging it in this example.
What rules am I violating by setting the __weak flag?
#import "FFAppDelegate.h"
///////////////////////////////////////////////////////
#interface SomeObject : NSObject
#end
#implementation SomeObject
- (NSString *)description; {
return #"SomeObject";
}
#end
///////////////////////////////////////////////////////
#interface Factory : NSObject
#end
#implementation Factory
- (id)generateObj {
id myObj = nil;
if (!myObj) {
SomeObject *anObj = [[SomeObject alloc] init];
myObj = anObj;
}
return myObj;
}
#end
///////////////////////////////////////////////////////
#interface Bar : NSObject
- (id)barObj;
#end
#implementation Bar
{
Factory *factory;
}
- (id)init {
self = [super init];
if (self) {
factory = [[Factory alloc] init];
}
return self;
}
- (id)barObj {
id anObj = [factory generateObj];
return anObj;
}
#end
///////////////////////////////////////////////////////
#interface Foo : NSObject
#property (strong) Bar *aBar;
- (void)doSomething;
#end
#implementation Foo
- (id)init {
self = [super init];
if (self) {
_aBar = [[Bar alloc] init];
}
return self;
}
- (void)doSomething {
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{
__weak id myObj = [self.aBar barObj];
NSLog(#"My Obj - %#", myObj);
});
}
#end
///////////////////////////////////////////////////////
#implementation FFAppDelegate
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
{
Foo *f = [[Foo alloc] init];
[f doSomething];
}
#end
What rules am I violating by setting the __weak flag?
In your example, there is no strong reference to the instance returned from [self.aBar barObj]. Therefore, you cannot assume the instance will be alive by the time you read the myObj variable.
In the unoptimized build, the returned instance has been added to an autorelease pool and is therefore still alive when you print myObj. You can verify this by setting a breakpoint in -[SomeObject dealloc].
In the optimized build, ARC has avoided the autorelease pool and the returned instance is therefore deallocated immediately.
See section 3.2.3 in the Clang ARC documentation for more info. Specifically:
When returning from such a function or method, ARC retains the value at the point of evaluation of the return statement, then leaves all local scopes, and then balances out the retain while ensuring that the value lives across the call boundary. In the worst case, this may involve an autorelease, but callers must not assume that the value is actually in the autorelease pool.
When using __weak to avoid a retain cycle, you must ensure that there is a strong reference somewhere else to keep the object alive.
Maybe you should use Apple's default compiler LLVM and not GCC.
Edit: Also your "factory" method looks wrong. For example, the object is always nil in that if. Take a tour: http://developer.apple.com/library/ios/#documentation/general/conceptual/CocoaEncyclopedia/ClassFactoryMethods/ClassFactoryMethods.html
I'm running into some trouble implementing a simple super/sub class scheme. I declare an NSMutableDictionary in the superclass, and am trying to access it in a subclass, but it only returns null. Any help would be appreciated.
#interface RootModel : NSObject <Updatable, TouchDelegate>
#property (nonatomic) NSMutableDictionary *gameValues;
#end
#interface SubclassModel : RootModel
#end
#implementation RootModel
- (id)initWithController:(id)controller {
if ((self = [super init])) {
_controller = controller;
_gameValues = [NSMutableDictionary dictionaryWithObjectsAndKeys:
[NSNumber numberWithFloat:300.0f], KEY_JUMP_VELOCITY,
[NSNumber numberWithFloat:49.47f], KEY_GRAVITY,
[NSNumber numberWithFloat:0.25f], KEY_JUMP_TIME_LIMIT,
nil];
NSLog(#"%#", _gameValues);
}
return self;
}
#implementation SubclassModel
- (id)init{
if ((self = [super init])) {
// This NSLog prints "(null)" if using super.gameValues or self.gameValues, why?
NSLog(#"subclass: %#", super.gameValues);
}
return self;
}
#end
What am I doing wrong?
As Catfish_Man answered, your init method needs to call [super initWithController:]. However you seem to show a misunderstanding of the class/super class inheritance model with your comment:
My superclass is initialized by another controller class. Any calls to the super's properties (which were initialized in initWithController:) are valid (they return values, not null).
When you create an instance of your SubclassModel then that instance has as part of itself a RootModel instance. That RootModel instance is not shared with any other instance of SubclassModel or RootModel.
So if "another controller class" creates and initialises and instance of RootModel, which in turn displays your NSLog output, then that is a totally different object to your SubclassModel instance - and the RootModel that is part of your SubclassModel instance is not initialised, as you don't call [super initWithController:], hence you NSLog in SubclassModel shows nil.
Your subclass init method needs to call [super initWithController:], since that's where the actual initialization happens.
(or the superclass initWithController: needs to call [self init], and you need to move the initialization work you're relying on to init)
I'm new with objective c for the iphone.
I'm writing a custom class, then, should I write my own +alloc, +init methods?
I believe that: the +alloc will just call [thing alloc]; and the +init will perform something like: [thing setValue:X];
is there a "default" +alloc and +init methods?
if yes, what should I wait for the default +alloc and +init?, let's say i have a NSMutableDictionary*
i.e.
#interface class1 : NSObject {
NSString *test;
NSMutableDictionary *map;
}
thanks
You generally don't need to write your own +alloc method.
For your example, you might have an -init that looks like:
- (id)init {
self = [super init];
if (self) {
map = [[NSMutableDictionary dictionary] retain];
}
return self;
}
Note that you first call the superclass -init, and check that it worked, before initializing your own variables.
You should NEVER override alloc.
As for init, which is an instance method, by the way, yes that would be the place where you'd probably want to set up your variables.
I've got this code:
Entry.h
#import <Foundation/Foundation.h>
#interface Entry : NSObject {
id object;
SEL function;
}
#property (retain) id object;
#property (assign) SEL function;
-(Entry*) initWithObject:(id)object selector:(SEL)function;
#end
Entry.m
#import "Entry.h"
#implementation Entry
#synthesize object;
#synthesize function;
-(Entry*) initWithObject:(id)obj selector:(SEL)sel {
self = [super init];
[self setObject:obj];
[self setFunction:sel];
return self;
}
-(void) dealloc {
[super dealloc];
if ([self object] != nil)
[[self object] release];
}
#end
And when I do this:
Entry *hej = [Entry alloc];
[hej release];
I get:
objc[2504]: FREED(id): message object sent to freed object=0xf5ecd0
Program received signal: “EXC_BAD_INSTRUCTION”.
What am I doing wrong?
(And this insert code thing at stack overflow doesnt work, unless I'm doing something wrong and you're not supposed to click "code sample" and then paste.)
+alloc only allocates memory. You need -init to actually create the object in that memory space. Since you are only allocating memory and not creating an object there, calling -release on a chunk of memory is giving you an error. Further, you want your [super dealloc] call to appear at the end of you -dealloc method. Change those two things and the following should work:
Entry *hej = [[Entry alloc] init];
[hej release];
there are two problems here:
1) you need to check that self = [super init] does not return nil. Typical usage would be to follow wrap your initialization code with the conditional:
if ((self = [super init]) != nil) {
// initialize the object...
}
2) but where you are getting stuck is on instantiating your object: you should do it like this:
Entry *hej = [[Entry alloc] initWithObject:myObj selector:mySelector];
(assuming that you want to go through the custom initializer you just defined...
else just use the default init method.) but 'alloc' must be followed by an init.
Entry *hej = [[Entry alloc] init]; // will do the trick...
Firstly, you need an init to go with your alloc. Second, in dealloc, you send a message to self after calling [super dealloc]. You can't do that. The final deallocation should go at the end.
I would also recommend changing:
if ([self object] != nil)
[[self object] release];
to:
[self setObject:nil];
It's less code and functionally equivalent. =)
There are many things wrong with your code. I'll try to go through them.
First, its better to use a different ivar name to your property name so its clear where you are using each. Apple normally uses an underscore prefix, but any prefix will do.
#interface Entry : NSObject {
id _object;
SEL _function;
}
#property (retain) id object;
#property (assign) SEL function;
#synthesize object = _object;
#synthesize function = _function;
Next, you aren't using the standard init template (although this probably wont make any difference normally).
-(Entry*) initWithObject:(id)obj selector:(SEL)sel {
self = [super init];
if (self != nil) {
// initializations
}
return self;
}
Next, Apple (for good reasons) recommends against using getters/setters in your init/dealloc. So your init would be:
-(Entry*) initWithObject:(id)obj selector:(SEL)sel {
self = [super init];
if (self != nil) {
_object = [obj retain];
_object = sel;
}
return self;
}
Next, after [super dealloc] your object is destroyed, so you cannot reference self (and hence your ivars) after that, so your dealloc should look like:
-(void) dealloc {
// your deallocations
[super dealloc];
}
Further, as above, Apple recommends you should not use setters or getters in your dealloc routine, so your deallocation would initially look like:
if (_object != nil)
[_object release];
But further still, Objective C allows (and Cocoa encourages) that sending a method to nil does nothing. This is in stark contast to most other languages where messaging nil would cause a crash, but it is how Objective C/Cocoa work and you need to get used to it. So your deallocation is actually just:
[_object release];
And finally, alloc only allocates the memory for your object, you have to initialize it, so the initialization would be something like:
Entry *hej = [[Entry alloc] initWithObject:myobj selector:#selector(mymethod)];
I am using the iPhone SDK and have an issue doing something simple. I am trying to add an NSNumber object to an NSMutableArray instance variable. I tried adding NSNumber card to NSMutableArray viewedCardsArray, however without breaking, it does not get added to the array. Here is the code.
/////////////////////////////////////////////////////
// Inside the header file Class.h
#interface MyViewController : UIViewController {
NSMutableArray *viewedCardsArray;
//snip ...
}
#property (nonatomic, retain) NSMutableArray *viewedCardsArray;
#end
/////////////////////////////////////////////////////
// Inside the methods file Class.m
#import "StudyViewController.h"
#implementation StudyViewController
#synthesize viewedCardsArray
//snip ...
- (IBAction)doShowCard {
//snip ...
NSNumber *cardIdObject = [[NSNumber alloc] initWithInt:(int)[self.currentCard cardId]];
[viewedCardsArray addObject: cardIdObject];
[cardIdObject release];
}
So this code executes, and does not seem to leak (according to the Leaks performance tool). However when stepping through the code, at no point does CardIdObject appear in viewedCardsArray.
Looking through SO, I know these basic questions are pretty common to ObjC newbies (like me) so apologies in advance!
Have you initialized your viewedCardsArray? If not you need to somewhere - this is usually done in the init method for your class:
- (id)init
{
self = [super init];
if(self) {
viewedCardsArray = [[NSMutableArray alloc] init];
}
return self;
}
Then it is released in the dealloc method:
- (void)dealloc
{
[viewedCardsArray release];
[super dealloc];
}
Perspx has outlined one way of initializing the array. However, you can also use the class methods provided by NSArray:
self. viewedCardsArray = [NSMutableArray array];
This can go in init or elsewhere.
Note: The object will be autoreleased.