Objective-C - Having Trouble Following "Initializer Chain" - objective-c

Okay. Tough to find the best starting point, here. The error XCode (4.3.2) in Lion is kicking back to me is:
Redefinition of 'a' with a different type
The author says when we declare this line (near the bottom of this page, in main)...
OwnedAppliance *a = [[OwnedAppliance alloc] init];
...that it should run fine. It doesn't. It kicks back the error above. I understand that, because OwnedAppliance has no init method in its implementation, the compiler will go up the hierarchy to OwnedAppliance's superclass, which is Appliance, and search for an init method there. It finds the overridden init, which contains only the following line...
[self initWithProductName:#"Unknown"];
...and runs that. Understood.
Ugh. Sorry, guys. I just tried to explain what I think might be happening. It took a dozen lines and I'd just scratched the surface. Rather than bore you with what I think is happening, I'll just ask:
What's going on with this code? Where does the initialization "path", for lack of a better term, end? Where does the redefinition (the error) occur?
/******************** Appliance.h ********************/
#import <Foundation/Foundation.h>
#interface Appliance : NSObject
{
NSString *productName;
int voltage;
}
#property (copy) NSString *productName;
#property int voltage;
-(id)init;
// Designated initializer
-(id)initWithProductName:(NSString *)pn;
...
#end
/******************** Appliance.m ********************/
#import "Appliance.h"
#implementation Appliance
#synthesize productName, voltage;
-(id)init
{
return [self initWithProductName:#"Unknown"];
}
-(id)initWithProductName:(NSString *)pn
{
self = [super init];
if (self) {
[self setProductName: pn];
[self setVoltage: 120];
}
return self;
...
#end
/******************** OwnedAppliance.h ********************/
#import "Appliance.h"
#interface OwnedAppliance : Appliance
{
NSMutableSet *ownerNames;
}
// Designated initializer
-(id)initWithProductName:(NSString *)pn
firstOwnerName:(NSString *)n;
...
#end
/******************** OwnedAppliance.m ********************/
#import "OwnedAppliance.h"
#implementation OwnedAppliance
-(id)initWithProductName:(NSString *)pn
firstOwnerName:(NSString *)n
{
self = [super initWithProductName:pn];
if (self) {
ownerNames = [[NSMutableSet alloc] init];
if (n) {
[ownerNames addObject:n];
}
}
return self;
}
-(id)initWithProductName:(NSString *)pn
{
return [self initWithProductName:pn
firstOwnerName:nil];
}
...
#end
/******************** main.m ********************/
#import <Foundation/Foundation.h>
#import "Appliance.h"
#import "OwnedAppliance.h"
int main(int argc, const char * argv[])
{
#autoreleasepool {
// Previously omitted problematic code:
Appliance *a = [[Appliance alloc] init];
NSLog(#"a is %#", a);
[a setProductName:#"Washing Machine"];
[a setVoltage:240];
NSLog(#"a is %#", a);
// The following line is where the error occurs:
OwnedAppliance *a = [[OwnedAppliance alloc] init];
...
}
return 0;
}
I've thought a lot about this question and how to ask it. I don't think it's a terribly dumb one. :) But my brain is fried from 9 hours of studying this stuff, so I apologize if this is a totally obvious question. TIA
EDIT: main() now contains the code that was actually causing the error. Thanks to Jacques for being good enough to catch it despite the omission.

The compiler's actually telling you that the variable itself, a, has been declared twice; the error has nothing to do with the assignment. Somehwhere else, in scope, you have another variable named a, which has a different type than OwnedAppliance *. Change the name(s) of one (or both) and the error will go away.

Related

Why is it not giving memory leak?

I have this code (modified from a tutorial I am following):
#import <Foundation/Foundation.h>
#class Car;
#class Person;
#interface Person: NSObject
#property Car* owningCar;
#end
#implementation Person:NSObject
-(void)dealloc {
NSLog(#"Person is gone");
}
#end
#interface Car:NSObject
#property Person* owner;
#end
#implementation Car:NSObject
-(void)dealloc {
NSLog(#"Car is gone");
}
#end
void testRefCycle () {
Person* me = [[Person alloc] init];
Car* civic = [[Car alloc] init];
me.owningCar = civic;
civic.owner = me;
}
int main(int argc, const char * argv[]) {
#autoreleasepool {
testRefCycle();
}
return 0;
}
I opened up Profiler Leaks, and ran it, expecting to get Leaks, but nothing shows up. Why is there no leak if this creates a reference cycle?
When I ran the project, there is also no output. Why is there no output if there is no leaks?
There is a leak, which is why there is no output — your dealloc methods never run.
But the leak detector never has a chance to detect it, because your program comes to an end in a millionth of a second. You do not have any persistent state over the longer term, which is what is needed for something to count as a leak.
If you ran testRefCycle in an app, for example, where the app itself persists over time, you would see the leak reported. But you are not going to see it in a one-line command-line program without a run loop, which is what you've got.

Invoking function getting stuck in a recursive loop and never comes

I am learning Objective-C inheritance and my program is getting lost in a recursive loop and won't come out. It gets hung up when calling a getter function.
I am using XCode version: Version 6.2 (6C101)
My program is given below
Vehicle.h
#ifndef exercise_2_Vehicle_h
#define exercise_2_Vehicle_h
#import <Foundation/Foundation.h>
#interface Vehicle : NSObject
#property float speed;
-(void) start;
-(void) stop;
-(void) park;
#end
#endif
Vehicle.m
#import "Vehicle.h"
#implementation Vehicle
-(void) setSpeed:(float)speed {
self.speed = speed;
}
-(float) speed {
return self.speed;
}
-(void) start {
NSLog(#"Starting the vehicle");
}
-(void) stop {
NSLog(#"Stopping the vehicle");
}
-(void) park {
NSLog(#"Parking the vehicle");
}
#end
Car.h
#ifndef exercise_2_Car_h
#define exercise_2_Car_h
#import "Vehicle.h"
#interface Car : Vehicle
#property (nonatomic) NSString* make;
-(Car*) initMake: (NSString*) make;
-(NSString*) make;
#end
#endif
Car.m
#import "Car.h"
#implementation Car
-(Car*) initMake:(NSString *)make {
self = [super init];
if (self) {
self.make = make;
}
return self;
}
-(NSString*) make {
return self.make;
}
#end
main.m
#import <Foundation/Foundation.h>
#import "Car.h"
#import "Vehicle.h"
int main(int argc, const char * argv[]) {
#autoreleasepool {
// insert code here...
Car* car = [[[Car alloc] init] initMake: #"Camry"];
//[car setSpeed:45];
NSLog(#"The model initialized is ");
[car make];
// [car speed];
}
return 0;
}
The issue you have is caused by creating the property for speed:
#property float speed;
and overriding setSpeed: method.
When you create #property compiler adds two methods for you, in your example setSpeed and speed.
This command:
self.speed = speed;
is equal to:
[self setSpeed: speed];
and inside setSpeed you have this command again which cause the loop. In your example you can remove both methods (setSpeed and speed) because compiler will add it for you. If you need it because you want to do some customisation you should use _speed instead self.speed.
_speed is backed variable added by compiler when using #property.
Change your method to:
-(void) setSpeed:(float)speed {
_speed = speed;
}
to remove the infinite loop.
In the
- (NSString*)make;
use
return _make
instead. The same with the speed.
If you return "self.x" in a getter method, then it's going to try and call the method again because you're requesting it on self. XCode will automatically convert the properties into variables that can be accessed with an '_' character, so you don't need to do any extra work.
You could also ignore our advice and remove both the "speed" and "make" getter methods you have made, because XCode automagically creates them for you.

Incomplete Implementation Example Help!

I am working on an example from a book that I got and it doesnt seem to be working I am getting the warning Incomplete implementation. When I run the program I get an error singal "EXC_BAD_ACCESS". The warning is in the .m file at the line return [NSString stringWithFormat:#"Name:... Does anyone know what I am doing wrong?
my .m file
#import "RadioStation.h"
#implementation RadioStation
+ (double)minAMFrequency {
return 520.0;
}
+ (double)maxAMFrequency {
return 1610.0;
}
+ (double)minFMFrequency {
return 88.3;
}
+ (double)maxFMFrequency {
return 107.9;
}
- (id)initWithName:(NSString *)newName atFrequency:(double)newFreq atBand:(char)newBand {
self = [super init];
if (self != nil) {
name = [newName retain];
frequency = newFreq;
band = newBand;
}
return self;
}
- (NSString *)description {
return [NSString stringWithFormat:#"Name: %#, Frequency: %.1f Band: %#", name, frequency, band];
}
- (void)dealloc {
[name release];
[super dealloc];
}
#end
My .h file
#import <Cocoa/Cocoa.h>
#interface RadioStation : NSObject {
NSString *name;
double frequency;
char band;
}
+ (double)minAMFrequency;
+ (double)maxAMFrequency;
+ (double)minFMFrequency;
+ (double)maxFMFrequency;
-(id)initWithName:(NSString*)name
atFrequency:(double)freq
atBand:(char)ban;
-(NSString *)name;
-(void)setName:(NSString *)newName;
-(double)frequency;
-(void)setFrequency:(double)newFrequency;
-(char)band;
-(void)setBand:(char)newBand;
#end
radiosimulation.m file:
int main (int argc, const char * argv[]) {
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
// insert code here...
NSMutableDictionary* stations = [[NSMutableDictionary alloc] init];
RadioStation* newStation;
newStation = [[RadioStation alloc] initWithName:#"Star 94"
atFrequency:94.1
atBand:'F'];
[stations setObject:newStation forKey:#"WSTR"];
[newStation release];
NSLog(#"%#", [stations objectForKey:#"WSTR"]);
newStation = [[RadioStation alloc] initWithName:#"Rocky 99"
atFrequency:94.1
atBand:'F'];
[stations setObject:newStation forKey:#"WKFR"];
[newStation release];
NSLog(#"%#", [stations objectForKey:#"WKFR"]);
[stations release];
[pool drain];
return 0;
You are declaring the following property accessor/mutators (getter/setters) but are not implementing them in your .m file.
-(NSString *)name;
-(void)setName:(NSString *)newName;
-(double)frequency;
-(void)setFrequency:(double)newFrequency;
-(char)band;
-(void)setBand:(char)newBand;
You need to implement all 6 of these methods in the .m file if you want to remove the warning about incomplete implementation.
You are effectively saying in the .h file that this is what your object is going to do, then not doing it in the .m. It won't generate an error, as objective-c messaging means that the message will be handed up to NSObject to deal with, which will also not have any matching implementation, and the messages will just be silently ignored. I don't like the way that this is only shown as a warning - but there you go.
That said, I wouldn't create the properties like this (there are neater ways of doing this in objective-c using #property), I would remove those method declarations in the .h and replace them with:
#property (nonatomic, retain) NSString *name;
#property (nonatomic, assign) double frequency;
#property (nonatomic, assign) char band;
These property declarations go in the same place as method declarations.
and then add the following to the .m file:
#synthesize name;
#synthesize frequency;
#synthesize band;
This will avoid having to write all that boilerplate accessor/mutator code that you are currently missing. Again, these go in the same region of the code as method implementations. Effectively the compiler is going to create name and setName methods automatically.
This code is untested - but should point you in the right direction for tidying up the incomplete implementation. It may fix your access error too - but that may require more detailed look at a stack trace.
Another point I'm not sure the code as written even needs to use get/set methods or properties. You might try removing the method declarations from the .h and see if it works. It seems that all the accesses to name, frequency and band are all from within the object.

Objective-C Basic class related question, retaining the value of a specific object using a class file

Members, scholars, code gurus.
My background is far from any computer programming thus my question may seems basic and somewhat trivial to you. Nevertheless it seems that I can't put my head around it.
I have googled and searched for the answer, just to get myself confused even more.
With that, I would kindly ask for a simple explanation suitable for a non technical person such as myself and for other alike arriving to this thread.
I have left a comment with the text "Here is the issue" below, referring to my question.
// character.h
#import <Foundation/Foundation.h>
#interface character : NSObject {
NSString *name;
int hitPoints;
int armorClass;
}
#property (nonatomic,retain) NSString *name;
#property int hitPoints,armorClass;
-(void)giveCharacterInfo;
#end
// character.m
#import "character.h"
#implementation character
#synthesize name,hitPoints,armorClass;
-(void)giveCharacterInfo{
NSLog(#"name:%# HP:%i AC:%i",name,hitPoints,armorClass);
}
#end
// ClassAtLastViewController.h
#import <UIKit/UIKit.h>
#interface ClassAtLastViewController : UIViewController {
}
-(void)callAgain;
#end
// ClassAtLastViewController.m
#import "ClassAtLastViewController.h"
#import "character.h"
#implementation ClassAtLastViewController
- (void)viewDidLoad {
//[super viewDidLoad];
character *player = [[character alloc]init];
player.name = #"Minsc";
player.hitPoints = 140;
player.armorClass = 10;
[player giveCharacterInfo];
[player release];
// Up until here, All peachy!
[self performSelector:#selector(callAgain) withObject:nil afterDelay:2.0];
}
-(void)callAgain{
// Here is the issue, I assume that since I init the player again I loss everything
// Q1. I loss all the data I set above, where is it than?
// Q2. What is the proper way to implement this
character *player = [[character alloc]init];
[player giveCharacterInfo];
}
Many thanks in advance, Kindly remember that my background is more related to Salmons breeding than to computer code, try and lower your answer to my level if it's all the same to you.
I loss all the data I set above, where is it than?
It's been freed (released). Notice:
character *player = [[character alloc]init]; // You create the character here...
// And then you initialize it...
// Then later...
[player release]; // You release it.
Even if you didn't release it, you still wouldn't be able to access it from callAgain, because you declare player in viewDidLoad. If you want it available to all methods in instances of ClassAtLastViewController, you should make it an instance variable.
What is the proper way to implement this
I don't know the specifics of your usage, but I imagine you want something like this:
#interface ClassAtLastViewController : UIViewController {
character *player; // Make player an instance variable
}
-(void)callAgain;
#end
#implementation ClassAtLastViewController
- (void)viewDidLoad {
//[super viewDidLoad];
player = [[character alloc]init]; // Initialize the instance variable
player.name = #"Minsc";
player.hitPoints = 140;
player.armorClass = 10;
[player giveCharacterInfo];
[self performSelector:#selector(callAgain) withObject:nil afterDelay:2.0];
}
-(void)callAgain{
[player giveCharacterInfo];
}
When you init the character in your callAgain function, you are actually creating a second instance of character. Even though the character created in callAgain has the same name as the character you created in viewDidLoad, it is a completely separate variable. The character you init in viewDidLoad only exists in the scope of the viewDidLoad function.
Also, when you call [player release] in viewDidLoad, you are removing that character instance from memory.
I think what you want to do is to create an instance variable that can be used throughout your class:
// ClassAtLastViewController.h
#import <UIKit/UIKit.h>
#interface ClassAtLastViewController : UIViewController {
character *player;
}
-(void)callAgain;
#end
// ClassAtLastViewController.m
#import "ClassAtLastViewController.h"
#import "character.h"
#implementation ClassAtLastViewController
- (void)viewDidLoad {
//[super viewDidLoad];
player = [[character alloc]init];
player.name = #"Minsc";
player.hitPoints = 140;
player.armorClass = 10;
[player giveCharacterInfo];
[self performSelector:#selector(callAgain) withObject:nil afterDelay:2.0];
}
-(void)callAgain{
// Here is the issue, I assume that since I init the player again I loss everything
// Q1. I loss all the data I set above, where is it than?
// Q2. What is the proper way to implement this
[player giveCharacterInfo];
}

objective c Class code not executing? what is my problem?

Having some issues with code not executing within the classes I created and thought I initialized and implemented correctly here are all the files. There is a class with an array of another class. Then implemented in the code finally but for some reason none of the NSLog calls seem to execute except the one immediately before [mobdefs createTable] in the main code. All help appreciated...
// Mobdefs.h
#interface Mobdefs : NSObject {
#public NSMutableArray *mobInfo;
}
#property(retain) NSMutableArray *mobInfo;
-(void) createTable;
#end
// Mobdefs.m
#import "Mobdefs.h"
#import "Mobrec.h"
#implementation Mobdefs
#synthesize mobInfo;
- (id) init
{
mobInfo = [[NSMutableArray alloc] init];
return self;
}
-(void) addmobrec
{
MobRec *aNewMobRec = [[MobRec alloc] init];
aNewMobRec.mName=#"newbie";
[mobInfo addObject:aNewMobRec];
[aNewMobRec release];
NSLog(#"MobRec Added\n");
}
-(void) createTable
{
NSLog(#"Populating mob table.\n"); // *** THIS CODE NEVER SEEMS TO GET EXECUTED
}
#end
//main.h
Mobdefs *mobdef;
//main.m
NSLog(#"just before createTable call\n");
[mobdef createTable];
although the createTable code is called in the main the only NSLog output I get is the 'just before createtable...'
It doesn't seem that you have initialized mobdef. Add the following:
mobdef = [[Mobdefs alloc] init];
to your main.m before you invoke the method on it.
Objective-C silently ignore calls on nil, as mobdef would be initialized to initially.
are you allocating and initializing mobdef in main.m?