I have the Header of this class in my project:
#interface VideoItem : NSObject <NSCoding> {
NSString *idStr;
NSString *name;
NSString *link;
}
-(id)initWithVideoItem:(VideoItem*)video;
#property (nonatomic, retain) NSString *name;
#property (nonatomic, retain) NSString *link;
#property (nonatomic, retain) NSString *idStr;
#end
this is the implement:
#implementation VideoItem
#synthesize name,link,idStr;
-(id)initWithVideoItem:(VideoItem*)video{
if (self = [super init]) {
self.name = video.name;
self.link = video.link;
self.idStr = video.idStr;
}
return self;
}
#pragma mark
#pragma mark NSCoder
- (void)encodeWithCoder:(NSCoder *)encoder{
[encoder encodeObject:self.name forKey:#"video_name"];
[encoder encodeObject:self.link forKey:#"video_link"];
[encoder encodeObject:self.idStr forKey:#"video_id"];
[encoder encodeObject:self.imgUrl forKey:#"video_img"];
[encoder encodeObject:self.viewCount forKey:#"video_views"];
[encoder encodeObject:self.artist forKey:#"video_artist"];
[encoder encodeObject:self.timeStr forKey:#"video_timestr"];
[encoder encodeInt:self.seconds forKey:#"video_secondes"];
[encoder encodeInt:self.rating forKey:#"video_rating"];
[encoder encodeObject:self.pubDate forKey:#"pubDate"];
}
- (id)initWithCoder:(NSCoder *)decoder {
if(self = [super init]){
self.name = [decoder decodeObjectForKey:#"video_name"];
self.link = [decoder decodeObjectForKey:#"video_link"];
self.idStr = [decoder decodeObjectForKey:#"video_id"];
}
return self;
}
#end
And i want to know if in case like this i need to add dealloc method and release the strings or not?
Yes you should release the strings because when using the properties that retain objects.
- (void)dealloc {
[idStr release];
[name release];
[link release];
[super dealloc];
}
Normally you would copy the object in the init, this is a better way then since the orginal object can then savely be edited or released.
-(id)initWithVideoItem:(VideoItem*)video{
if ((self = [super init])) {
name = [video.name copy];
link = [video.link copy];
idStr = [video.idStr copy];
}
return self;
}
Since the copy method return a retained object you want to skip the property, since that would increase the retain count.
On a other note: the objective-c convention the private ivar should start with an _ to make it more obvious that they are not properties.
Use ARC and forget any problems related to memory management.
Even apple encourages using ARC whenever possible. If you are doing this as a new development, I would recommend you to use ARC.
In case you do not want to use ARC, you need to implement dealloc and release your member variables.
Use this, release all your allocated variables and at last call super dealloc :
- (void)dealloc{
[idStr release];
[name release];
[link release];
[super dealloc];
}
you have to write
- (void)dealloc
Method as you are retaining the variable's. and release these variables in this method.
You are retaining your string properties.
So it's your task to release it.
So add a dealloc method and release them.
- (void)dealloc
{
[idStr release];
[name release];
[link release];
[super dealloc];
}
In fact you need not call the release on the ivars. Instead use the properties
self.ivar = nil. This releases your memory and sets the pointes to nil as a result of it there are no dangling pointers.
if you use [ivar release], ivar is released but is a dangling pointer, so most of the time ivar = nil; is done after releasing the ivar.
- (void)dealloc
{
self.idStr = nil;
self.name = nil;
self.link = nil;
[super dealloc];
}
Related
This question already has answers here:
Objective C - How do I use initWithCoder method?
(2 answers)
Closed 9 years ago.
I was reading about initializing the archived objects from a XIB file and found that
- (id)initWithCoder:(NSCoder *)aDecoder
is a way of doing it. But I am not able to get a hang around this. Can someone show me an simple example of how to do this?
Thanks a ton
The NSCoder class is used to archive/unarchive (marshal/unmarshal, serialize/deserialize) of objects.
This is a method to write objects on streams (like files, sockets) and being able to retrieve them later or in a different place.
I would suggest you to read Archiving
You also need to define the following method as follows:
- (void)encodeWithCoder:(NSCoder *)enCoder
{
[super encodeWithCoder:enCoder];
[enCoder encodeObject:instanceVariable forKey:INSTANCEVARIABLE_KEY];
// Similarly for the other instance variables.
....
}
And in the initWithCoder method initialize as follows:
- (id)initWithCoder:(NSCoder *)aDecoder
{
if(self = [super initWithCoder:aDecoder]) {
self.instanceVariable = [aDecoder decodeObjectForKey:INSTANCEVARIABLE_KEY];
// similarly for other instance variables
....
}
return self;
}
You can initialize the object standard way i.e
CustomObject *customObject = [[CustomObject alloc] init];
Example taken from this answer
You can use it in following way:
.h file
#interface Score : NSObject {
NSString *Username;
NSString *TotalPoints;
NSString *LifeRemains;
NSString *ScoreDate;
}
#property (nonatomic, retain) NSString *Username;
#property (nonatomic, retain) NSString *TotalPoints;
#property (nonatomic, retain) NSString *LifeRemains;
#property (nonatomic, retain) NSString *ScoreDate;
in .m file
#synthesize Username, TotalPoints, LifeRemains, ScoreDate;
- (void)encodeWithCoder:(NSCoder *)encoder
{
//Encode properties, other class variables, etc
[encoder encodeObject:self.Username forKey:kScoreUsername];
[encoder encodeObject:self.TotalPoints forKey:kScoreTotalPoints];
[encoder encodeObject:self.LifeRemains forKey:kScoreLifeRemains];
[encoder encodeObject:self.ScoreDate forKey:kScoreDate];
}
- (id)initWithCoder:(NSCoder *)decoder
{
self = [super init];
if( self != nil )
{
//decode properties, other class vars
self.Username = [decoder decodeObjectForKey:kScoreUsername];
self.TotalPoints = [decoder decodeObjectForKey:kScoreTotalPoints];
self.LifeRemains = [decoder decodeObjectForKey:kScoreLifeRemains];
self.ScoreDate = [decoder decodeObjectForKey:kScoreDate];
}
return self;
}
Happy Coding...
How to serialize the following class in objective-c so that it can be used with SBJson?
I get "JSON serialisation not supported for Animal" error when I use this code.
Can someone point out where I am going wrong?
The contents of Animal.h file is as below
#import <UIKit/UIKit.h>
#interface Animal : NSObject<NSCoding> {
NSString *name;
NSString *description;
NSString *imageURL;
}
#property (nonatomic, retain) NSString *name;
#property (nonatomic, retain) NSString *description;
#property (nonatomic, retain) NSString *imageURL;
-(id)initWithName:(NSString *)n description:(NSString *)d url:(NSString *)u;
#end
The contents of Animal.m file is as below
#import "Animal.h"
#implementation Animal
#synthesize name, description, imageURL;
-(id)initWithName:(NSString *)n description:(NSString *)d url:(NSString *)u {
self.name = n;
self.description = d;
self.imageURL = u;
return self;
}
- (id)initWithCoder:(NSCoder *)aDecoder
{
if(self = [super initWithCoder:aDecoder])
{
name = [[aDecoder decodeObjectForKey:#"name"] retain];
description = [[aDecoder decodeObjectForKey:#"description"] retain];
imageURL = [[aDecoder decodeObjectForKey:#"imageURL"] retain];
}
return [self initWithName:name description:description url:imageURL];
}
- (void)encodeWithCoder:(NSCoder *)encoder
{
[super encodeWithCoder:encoder];
[encoder encodeObject:name forKey:#"name"];
[encoder encodeObject:description forKey:#"description"];
[encoder encodeObject:imageURL forKey:#"imageURL"];
}
#end
Make your custom class conform to NSCoding protocol and then serialize it.
For more info, visit the Apple documentation
Also, this link will also help you.
As suggested in this link, archive your custom class to NSData and serialize that as provided in the Apple documentation.
Edit
Make your Animal.m as follows:
#import "Animal.h"
#implementation Animal
#synthesize name, description, imageURL;
-(id)initWithName:(NSString *)n description:(NSString *)d url:(NSString *)u {
self = [super init];
if( self )
{
self.name = n;
self.description = d;
self.imageURL = u;
}
return self;
}
- (id)initWithCoder:(NSCoder *)aDecoder
{
self = [super init];
if( self )
{
self.name = [aDecoder decodeObjectForKey:#"name"];
self.description = [aDecoder decodeObjectForKey:#"description"];
self.imageURL = [aDecoder decodeObjectForKey:#"imageURL"];
}
return self;
}
- (void)encodeWithCoder:(NSCoder *)encoder
{
[encoder encodeObject:name forKey:#"name"];
[encoder encodeObject:description forKey:#"description"];
[encoder encodeObject:imageURL forKey:#"imageURL"];
}
#end
To actually answer your question on how to do it using SBJson: Implement the proxyForJson method. Unless you are serializing an NSArray or NSDictionary you must override this method for serialization to work.
You can see that this is the case by looking at the SBJson source code (in SBJsonWriter.m):
- (NSData*)dataWithObject:(id)object {
...
if ([object isKindOfClass:[NSDictionary class]])
ok = [streamWriter writeObject:object];
else if ([object isKindOfClass:[NSArray class]])
ok = [streamWriter writeArray:object];
else if ([object respondsToSelector:#selector(proxyForJson)])
return [self dataWithObject:[object proxyForJson]];
else {
self.error = #"Not valid type for JSON";
return nil;
}
...
}
}
Implement proxyForJson in Animal.m like this (not tested):
- (NSDictionary*) proxyForJson
{
return [NSDictionary dictionaryWithObjectsAndKeys:self.name, #"name",
self.description, #"description",
self.imageURL, #"imageURL",
nil];
}
This open source project JSONCoding makes the whole process pretty simple, using the new sdk class in conjunction with the NSCoding protocol.
Check the newly introduced NSJSONSerialization class:
NSJSONSerialization class
I think you can check out this if it helps you: Make a Custom Class Serializable
Please check this Property List Programming Guide - Serializing a Property List
and the similar post here:
Make a Custom Class Serializable in Objective-c/iPhone?
Object serialization in XML format using Obj-C / iPhone SDK
See also https://github.com/jsonmodel/jsonmodel
Magical Data Modeling Framework for JSON - allows rapid creation of
smart data models. You can use it in your iOS, macOS, watchOS and tvOS
apps.
This is also the chosen library for the Objective-c Swagger client.
getting a memory SIGBUS error when adding a custom object to a mutableArray in objective c.
#interface stak : NSObject {
NSString *idval,
*username,
*userid,
*password,
*snippet,
*curStakId,
*pageCount,
*memberCount,
*imgURL,
*tags;
UIImage *icon;
}
#property (nonatomic,retain) NSString *idval,*username,*userid,*password,*curStakId,*snippet,*pageCount,*memberCount,*imgURL,*tags;
#property (nonatomic,retain) UIImage *icon;
-(id)initWithidval:(NSString *)idvalue
username:(NSString *)user
userid:(NSString *)uid
password:(NSString *)pass
curStakId:(NSString *)stakid
snippet:(NSString *)snip
pageCount:(NSString *)page
memberCount:(NSString *)members
tags:(NSString *)tag_vals
imgURL:(NSString *)img
icon:(UIImage *)iconImg;
#end
and the .m
#implementation stak
#synthesize idval;
#synthesize username;
#synthesize userid;
#synthesize password;
#synthesize curStakId;
#synthesize snippet;
#synthesize pageCount;
#synthesize memberCount;
#synthesize imgURL;
#synthesize icon;
#synthesize tags;
-(id)initWithidval:(NSString *)idvalue
username:(NSString *)u
userid:(NSString *)uid
password:(NSString *)p
curStakId:(NSString *)stakid
snippet:(NSString *)snip
pageCount:(NSString *)page
memberCount:(NSString *)members
tags:(NSString *)tag_vals
imgURL:(NSString *)img
icon:(UIImage *)iconImg{
if (self = [super init]) {
[self setIdval:idvalue];
[self setUsername:u];
[self setUserid:uid];
[self setPassword:p];
[self setCurStakId:stakid];
[self setSnippet:snip];
[self setPageCount:page];
[self setMemberCount:members];
[self setTags:tag_vals];
[self setImgURL:img];
[self setIcon:iconImg];
}
return self;
}
-(void)dealloc{
[idval release];
[username release];
[userid release];
[snippet release];
[imgURL release];
[icon release];
[tags release];
[curStakId release];
[memberCount release];
[password release];
[super dealloc];
}
#end
and this is where it is called and released.
NSMutableArray *_return_staks = [[NSMutableArray alloc]init];
stak *_stakItem = [[stak alloc]initWithidval:[NSString stringWithFormat:#"%#",[staks objectAtIndex:i]]
username:[NSString stringWithFormat:#"%#",[creators objectAtIndex:i]]
userid:[NSString stringWithFormat:#"%#",[creatorid objectAtIndex:i]]
password:[NSString stringWithFormat:#"%#",[privacy objectAtIndex:i]]
curStakId:[NSString stringWithFormat:#"%#",[idvals objectAtIndex:i]]
snippet:tempString
pageCount:tempPcount
memberCount:tempMcount
tags:[NSString stringWithFormat:#"%#",[tags objectAtIndex:i]]
imgURL:[NSString stringWithFormat:#"%#",[img objectAtIndex:i]]
icon:nil];
[_return_staks addObject:_stakItem];
[_stakItem release];
When i go to reference the stored item i get a SIGBUS error, however when i remove the "[_stakItem release]" it works fine, however this creates a leak. Is there any way to correct this?
It's difficult to give you a definitive answer without seeing the context of the actual crash, but you are probably over releasing _stackItem somewhere. This is probably caused by keeping a reference to it but releasing the array which is the only thing that owns it. There is actually nothing wrong with the code you have posted (well, your string properties should really be copy properties, but that is not what is causing your crash).
Are you using _stakItem after the release?
Do you have a sequence like:
stak* foo = [_return_staks objectAtIndex: fooIndex];
// etc
[_return_staks release];
// etc
[foo doSomething]; // Likely to have gone away by now.
I am getting memory leak theFileName = [[responseString lastPathComponent]stringByDeletingPathExtension];
theFileName is a global variable. I have synthesized it and
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
if ((self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil]))
{
// Custom initialization
theFileName = [[NSString alloc] init];
}
return self;
}
- (void)requestFinished:(ASIHTTPRequest *)request{
//internally calls this function
// Use when fetching text data
NSString *responseString = [request responseString];
//NSLog(#"the responsestring for download is:%#",responseString);
theFileName = [[responseString lastPathComponent]stringByDeletingPathExtension];
//NSLog(#"the theFileName for download is:%#",theFileName);
//adds extension .jpg to file name
NSString *jpg=#".jpg";
NSString *addjpg=[theFileName stringByAppendingString:jpg];
//NSLog(#"append %#",addjpg);
}
Released it in dealloc.
-(void)dealloc
{
[thefileName release];
}
}
theFileName = [[responseString lastPathComponent]stringByDeletingPathExtension];
creates a new object for theFileName, which already holds an NSString object. You need to release that old value before, i.e.
[theFileName release];
theFileName = [[responseString lastPathComponent]stringByDeletingPathExtension];
You might consider using a copy (recommended) or retain property for theFilename, and use the dot-syntax in requestFinished:.
Here are a few things that might help.
You're not calling super's dealloc method within self's dealloc. For example,
- (void) dealloc
{
[self.theFileName release];
[super dealloc];
}
You're not using the getters and setters that come with synthesizing a property, and we don't know what property you've used with theFileName. If you've got a retaining property, i.e. a statement like #property (copy) NSString * theFileName then you should use the setter so that you don't trip up on retain counts. For example,
(id) initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
if ((self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil]))
{
// Custom initialization
NSString * aFileName = [[NSString alloc] init];
[self setTheFileName:aFileName];
[aFileName release];
}
return self;
}
is better.
I hope to add objects to a NSMutableArray "myArray", The NSMutableArray is the array for FileObj which has a NSString property "fileName"
#import <UIKit/UIKit.h>
#interface FileObj : NSObject {
NSString *fileName;
}
-(void) setfileName:(NSString *)s ;
-(NSString *) getfileName ;
#end
//
// File.m//
#import "File.h"
#implementation FileObj
-(void) setfileName:(NSString *)s ;
{
fileName=s;
}
-(NSString *) getfileName ;
{
return fileName;
}
#end
I initialize the myArray here:
NSMutableArray *temarray;
temarray=[[NSMutableArray alloc] init];
self.myArray=temarray;
[temarray release];
the codes to add object to myArray
FileObj *newobj=[[FileObj alloc]init ];
NSString *fieldValue2 = [[NSString alloc] initWithUTF8String:#"aaaa"];
[newobj setfileName:fieldValue2];
[myArray addObject:newobj];
[fieldValue2 release]; //**if I enabled the line, it will cause crash**
//**if I disable the line, it will cause memory leak**
[newobj release];
Welcome any comment
Thanks
interdev
First you should look into ObjC naming conventions. There is no -get methods in ObjC. It's also a good idea to prefix your classes with your own 2 letters (like NS).
Your setter value assignment is invalid and the NSString initialization unnecessary.
I would strongly recommend introductory material to you!
#interface MYFileObject : NSObject {
NSString *_fileName;
}
- (void)setFileName:(NSString *)theString;
- (NSString *)fileName;
#end
and the implementation
#implementation MYFileObject
- (void)setFileName:(NSString *)theString {
[_fileName release];
_fileName = [theString copy];
}
- (NSString *)fileName {
return [[_fileName copy] autorelease];
}
- (void)dealloc {
[_fileName release];
[super dealloc];
}
#end
You would add an object like this...
NSMutableArray *myAry = [[NSMutableArray alloc] init];
MYFileObject *obj = [[MYFileObject alloc] init];
[obj setFileName:#"thefilename.txt"];
[myAry addObject:obj];
[obj release];
I would recommend using properties instead of defining your own getters/setters.
You could also use the NSMutableArrays' designated initializers for fast array creation.
Look here for how to use properties: http://developer.apple.com/mac/library/documentation/cocoa/Conceptual/ObjectiveC/Articles/ocProperties.html
Why bother with getters and setters? Use declared property already!
#interface FileObj : NSObject {
NSString *fileName;
}
#property(retain,nonatomic) NSString* fileName; // <---
#end
...
#implementation FileObj
#synthesize fileName; /// <---
-(void)dealloc {
[fileName release]; // Remember to release the object on dealloc.
[super dealloc];
}
#end
...
FileObj *newobj=[[FileObj alloc] init];
NSString *fieldValue2 = [[NSString alloc] initWithUTF8String:#"aaaa"];
newobj.fileName = fieldValue2; /// <----
[myArray addObject:newobj];
[fieldValue2 release];
[newobj release];
The crash occurs because the NSString instance is not retained anymore.
A common pattern is to retain NSString properties, either declaratively with #property or by hand.
You should modify the setter like this:
-(void) setfileName:(NSString *)s ;
{
[s retain]; // <- Retain new value
[filename release]; // <- Release old value
fileName=s;
}