Objective C class initialization errors - objective-c

I have the following objective C class. It is to store information on a film for a cinema style setting, Title venue ID etc. Whenever I try to create an object of this class:
Film film = [[Film alloc] init];
i get the following errors: variable-sizedobject may not be initialized, statically allocated instance of Objective-C class "Film", statically allocated instance of Objective-C class "Film".
I am pretty new to Objective C and probably am still stuck in a C# mindset, can anyone tell me what I'm doing wrong?
Thanks michael
code:
// Film.m
#import "Film.h"
static NSUInteger currentID = -1;
#implementation Film
#synthesize filmID, title, venueID;
-(id)init {
self = [super init];
if(self != nil) {
if (currentID == -1)
{
currentID = 1;
}
filmID = currentID;
currentID++;
title = [[NSString alloc] init];
venueID = 0;
}
return self;
}
-(void)dealloc {
[title release];
[super dealloc];
}
+(NSUInteger)getCurrentID {
return currentID;
}
+(void)setCurrentID:(NSUInteger)value {
if (currentID != value) {
currentID = value;
}
}
#end
// Film.h
#import <Foundation/Foundation.h>
#interface Film : NSObject {
NSUInteger filmID;
NSString *title;
NSUInteger venueID;
}
+ (NSUInteger)getCurrentID;
+ (void)setCurrentID:(NSUInteger)value;
#property (nonatomic) NSUInteger filmID;
#property (nonatomic, copy) NSString *title;
#property (nonatomic) NSUInteger venueID;
//Initializers
-(id)init;
#end

You need your variable that holds the reference to your object to be of a reference type. You do this by using an asterisk - see below:
Film *film = [[Film alloc] init];
Coming from Java I often think of the above as:
Film* film = [[Film alloc] init];
I tend to associate the 'reference' marker with the type. But hopefully someone more versed in C/C++/ObjC will tell me why this is wrong, and what the 'asterisk' is actually called in this context.

Related

With ARC , why the dealloc not called

I have enable the ARC. but this code makes me wonder
#interface Dog : NSObject
#end
#implementation Dog
- (void)dealloc
{
printf("Dog is dealloc\n"); //the function not called
}
#end
#interface Person : NSObject
#property (nonatomic, strong) Dog *dog;
#end
#implementation Person
- (void)dealloc
{
printf("Person is dealloc\n");
_dog = nil;
}
-(Dog *)dog
{
return _dog;
}
#end
int main()
{
Person *p = [[Person alloc] init];
p.dog = [[Dog alloc]init];
Dog* d = p.dog;
d=nil;
p=nil;
printf("end\n");
return 0;
}
the result is
Person is dealloc
end
Program ended with exit code: 0
why the dog's dealloc method not called.
and then I commented out this Method, the dog's dealloc method called.
//-(Dog *)dog
//{
// return _dog;
//}
thank you very much.
You can see the memory graph to find out what exactly points to the Dog and preserve it from automatically deallocation:
Unlike Swift, In Objective-C, you need to put the main body inside an #autoreleasepool to make it ARC compatible:
int main(int argc, const char * argv[]) {
#autoreleasepool {
// insert code here...
NSLog(#"Hello, World!");
Person *p = [[Person alloc] init];
p.dog = [[Dog alloc]init];
Dog* d = p.dog;
d = nil;
p = nil;
printf("Ended...\n");
}
return 0;
}
Then you will see this in the output:
Person is dealloc
Ended...
Dog is dealloc

Objective-C: How to create object instance with constructor that references arrays

I'm trying to create an array of objects, but it's not working as expected. I have a Person class with a name property and I'm trying to instantiate Person objects with the names from another array like the code below. Instead of the names in the names array being used, the program outputs "(null)". So that means that it's not working as expected.
ViewController.m
names = [NSArray arrayWithObjects:#"Mike", #"John", #"Jimmy", #"Tim", nil];
personsArray = [[NSMutableArray alloc] initWithCapacity:4];
for (int i = 0; i <= 4; i++) {
Person *person = [[Person alloc] initWithName:[names objectAtIndex:i]];
NSLog(#"%#", [person name]); // outputs "(null)"
[personsArray addObject:person];
}
Person.m
#import "Person.h"
#implementation Person
-(id)initWithName:(NSString *)name {
if (self = [super init]) {
name = name;
}
return self;
}
#end
Person.h
#import <Foundation/Foundation.h>
#interface Person : NSObject
#property (nonatomic, strong) NSString *name;
-(id)initWithName:(NSString *)name;
#end
Please help!
This line in -[Person initWithName:] is your problem:
name = name;
You are just assigning the argument variable to itself. You need to assign the instance variable. You probably want to copy the input string, so:
_name = [name copy];

NSMutableArray: add and extract struct

I'm trying to store some data in an NSMutableArray. This is my struct:
typedef struct{
int time;
char name[15];
}person;
This is the code to add a person:
person h1;
h1.time = 108000;
strcpy(h1.name, "Anonymous");
[highscore insertObject:[NSValue value:&h1 withObjCType:#encode(person)] atIndex:0];
So, I try to extract in this way:
NSValue * value = [highscore objectAtIndex:0];
person p;
[value getValue:&p];
NSLog(#"%d", p.time);
The problem is that the final log doesn't show me 108000!
What is wrong?
Your code looks correct (and works for me), so I deduce that you aren't initializing highscore. So when you send the insertObject:atIndex: message to it, nothing happens. When you then send the objectAtIndex: method to it, you get nil back. When you send getValue: to the nil NSValue *value, it does nothing, so your person p is left filled with random stack garbage, which is why your NSLog doesn't print 108000.
As stated in my initial comment there rarely is a reason to do this kind of stuff with pure c structs. Instead go with real class objects:
If you're unfamiliar with the syntax below you may want to look at these quick tutorials on ObjC 2.0 as well as read Apple's documentation:
A Quick Objective-C 2.0 Tutorial
A Quick Objective-C 2.0 Tutorial: Part II
Person Class:
// "Person.h":
#interface Person : NSObject {}
#property (readwrite, strong, nonatomic) NSString *name;
#property (readwrite, assign, nonatomic) NSUInteger time;
#end
// "Person.m":
#implementation Person
#synthesize name = _name; // creates -(NSString *)name and -(void)setName:(NSString *)name
#synthesize time = _time; // creates -(NSUInteger)time and -(void)setTime:(NSUInteger)time
#end
Class use:
#import "Person.h"
//Store in highscore:
Person *person = [[Person alloc] init];
person.time = 108000; // equivalent to: [person setTime:108000];
person.name = #"Anonymous"; // equivalent to: [person setName:#"Anonymous"];
[highscore insertObject:person atIndex:0];
//Retreive from highscore:
Person *person = [highscore objectAtIndex:0]; // or in modern ObjC: highscore[0];
NSLog(#"%#: %lu", person.name, person.time);
// Result: "Anonymous: 108000"
To simplify debugging you may also want Person to implement the description method:
- (NSString *)description {
return [NSString stringWithFormat:#"<%# %p name:\"%#\" time:%lu>", [self class], self, self.name, self.time];
}
which will allow you to just do this for logging:
NSLog(#"%#", person);
// Result: "<Person 0x123456789 name:"Anonymous" time:108000>
Reimplement Person as an Objective-C object and reap the benefits:
Person.h:
#interface Person : NSObject
{
int _time;
NSString *_name;
}
#property (assign, nonatomic) int time;
#property (retain, nonatomic) NSString *name;
#end
Person.m:
#import "Person.h"
#interface Person
#synthesize time = _time;
#synthesize name = _name;
- (id)init
{
self = [super init];
if (self != nil)
{
// Add init here
}
return self;
}
- (void)dealloc
{
self.name = nil;
[super dealloc];
}
#end

Could there be an issue with the max. memory capacity? Or why is this variable partly released?

I'm developing an iPad app and I ran into a really weird issue here. I'll try to explain it as good as possible.
I have a class named TranslationObject which is holding a key and a textual value. I have created this class as the following:
#interface TranslationObject : NSObject {
NSNumber *_key;
NSString *_value;
}
#property (nonatomic, retain) NSNumber *key;
#property (nonatomic, retain) NSString *value;
- (id) initWithKey:(NSNumber *) key andValue:(NSString *) value;
#end
The translations will be pulled from a XML or DB in the future, but for now I do the following:
#interface Translation : NSObject {
NSMutableArray *m_extfeat;
}
#property (nonatomic, retain) NSMutableArray *extfeat;
+ (Translation *) getInstance;
- (id) init;
- (NSMutableArray *) getExtFeat;
#end
Implementation:
#implementation Translation
#synthesize extfeat = m_extfeat;
- (id) init {
self = [super init];
if (self) {
m_extfeat = [[self getExtFeat] retain];
}
return self;
}
- (NSMutableArray *) getExtFeat {
TranslationObject *obj1 = [[[TranslationObject alloc] initWithKey:[NSNumber numberWithInt: 0] andValue:#"Animal house"] autorelease];
.... more items declared ....
NSMutableArray *array = [[NSMutableArray alloc] initWithObjects:obj1, obj2, obj3, obj4, obj5, obj6, obj7, obj8, obj9, obj10, obj11, obj12, obj13, obj14, obj15, obj16, obj17, nil];
return [array autorelease];
}
#end
These translations are being used in a UITableViewController and are being fetched in the viewDidLoad method as:
- (void)viewDidLoad
{
_data = [[Translation getInstance].extfeat retain];
}
I use these values at its cellForRowAtIndexPath, where I call a method to configure the cell:
- (void) configureCell:(UITableViewCell *)cell atIndexPath:(NSIndexPath *) indexPath {
TranslationObject *object = (TranslationObject *) [_data objectAtIndex:indexPath.row];
//Crashes here at 13th item:
NSLog("Object key: %#", [object.key stringValue]);
}
As the snippet above says, strangely, the app crashes when fetching the key value only if the _data array contains more than 12 items. So if I only fill the _data variable with 12 items or less, my code works fine. If I add more than 12, the app crashes as soon as it fetches the 13th object.
So I enabled NSZombies and so when I check the 13th item in that method, the value is still fine, but it's only the key that turned into a Zombie. And again.. Only from the 13th item on!
Does anyone know how this is possible? Is it maybe so that there is a maximum number of items that can be stored in the memory? Is the memory full at the 12 item? But if that'd be the case, then why would the value still be there. How would it be possible that it's just the key that is being released before?! And how?!
I hope this explanation makes sense and someone can shine a light over this case.. =/
Thanks!
EDIT: Here's the implementation of the initWithKey method of the TranslationObject:
- (id) initWithKey:(NSNumber *) key andValue:(NSString *) value {
self = [super init];
if (self) {
_key = key;
_value = value;
}
return self;
}
Make sure your using the property accessors in the TranslationObject or retaining the number:
#implementation TranslationObject
#synthesize key=_key, value=_value;
- (id) initWithKey:(NSNumber *) key andValue:(NSString *) value {
self = [super init];
if (!self) return nil;
self.key = key; // ensures key is retained
self.value = value;
return self;
}
…
#end
Specifics:
self.key = key;
is the syntax for calling the accessor methods for the property; in this case the set accessor. Given you declared your property with the nonatomic and retain attributes as follows:
#property (nonatomic, retain) NSNumber *key;
the set accessor will look something like
- (void)setKey:(NSNumber *)value {
if (value != _key) {
id old = _key;
[value retain];
_key = value
[old release];
}
}
The set accessor is automatically generated by the compiler when you added:
#synthesize key=_key;
Conversely, calling
_key = key;
simply copies the value of the pointer in key to _key, but does not retain the object referred to by key. TranslationObject does not assume ownership of key. If you did not want to use the accessor, the correct implementation would be
_key = [key retain];

Objective-C error EXC_BAD_ACCESS help please

I am currently using the pragmatic screencast on Objective-C to help me program in objective-c. I have a background in Java and C++, but I am having a very difficult time getting used to everything in Objective(Mostly because I am not comfortable with the syntax).
Below is the error I am receiving with all the code.
I am also getting a warning in movie.m class as well: Wirtable atomic property 'title'
cannot be pair a synthesized setter/getter with a user defined setter/getter
thanks for your help.
I am receive this error
Current language: auto; currently objective-c
warning: Couldn't find class validation function, calling methods on uninitialized objects may deadlock your program.
Program received signal: “EXC_BAD_ACCESS”.
I ran it through the debugger and the address of movie in the code below is in red
main.m
int main (int argc, const char * argv[]) {
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
Movie *movie = [[Movie alloc] initWithTitle:#"iron man"
andRating:5
andYear:2008];
[movie play];
NSLog(#"our movie is %#", movie);
[pool drain];
return 0;}
Movie.h
interface Movie : NSObject {
NSString *title;
int rating;
int year;
}
- (id)initWithTitle:(NSString *)newTitle
andRating:(int)newRating
andYear:(int) year;
#property(assign) NSString *title;
#property(assign) int rating;
#property(assign) int year;
-(void) play;
#end
Movie.m
#import "Movie.h"
#implementation Movie
#synthesize title;
#synthesize rating;
#synthesize year;
-(id)initWithTitle:(NSString *)newTitle
andRating:(int)newRating
andYear:(int)newYear;
{
self = [super init];
if(nil != self){
self.title = newTitle;
self.rating = newRating;
self.year = newYear;
}
return self;
}
-(NSString *) description{
NSString *oldDescription = [super description];
return [NSString stringWithFormat: #"%# title =%#, rating =%d year=%#",
oldDescription, self.title, self.rating, self.year];
}
- (void)setTitle:(NSString *)newTitle {
title = [newTitle capitalizedString];
}
-(void) play {
NSLog(#"Playing %#", self);
}
You use year=%# when it should be year=%d.
Some more random thoughts:
You should retain or better even copy the title instead of assigning it.
The init method should be named
-(id)initWithTitle:(NSString *)aTitle
rating:(int)aRating
year:(int)aYear;
Don't forget a dealloc method then.
Your title property is an object type and so should in generally be either retain or copy -- in the case of NSString properties, it is traditional to use copy to avoid issues when you're passed an NSMutableString instead.
#property (copy) NSString* title;
Since you explicitly define the setter, you then need to implement this policy yourself, something like this:
- (void)setTitle:(NSString *)newTitle
{
[title release];
title = [[newTitle capitalizedString] copy];
}
You'll also need to include a dealloc method to clean up:
- (void) dealloc
{
[title release];
[super dealloc];
}