My custom class object gets released even after retaining it - ios4

I have been trying to debug this error like for days and still can't seem to grasp what really is going on with my object.
The code goes like this.
- (BOOL)webView:(UIWebView*)webView shouldStartLoadWithRequest:(NSURLRequest*)request navigationType:(UIWebViewNavigationType)navigationType {
// extract data from clicked link
SongObject *Data = [[SongObject alloc] init];
[Data retain];
selectedSong = Data;
}
selectedSong is public variable in the main class, now the crazy thing is that using the above method works everywhere else but shoulStartLoadWithRequest.
Trying to deubg it gives me "Out Of Scope", could it be by some crazy reason that "shouldStartLoadWithRequest" is autoreleasing my object even when I say don't?
Any idea's?
Edit: This is the H and M file which selectedSong is suppose to hold.
#import <Foundation/Foundation.h>
#import "SongObject.h"
#interface SongObject : NSObject<NSCopying> {
NSString *artist;
NSString *titel;
NSString *album;
NSString *genre;
NSString *songUrl;
NSString *rating;
NSString *image;
BOOL local;
}
#property (readonly) NSString *getArtist;
#property (readonly) NSString *getTitle;
#property (readonly) NSString *getAlbum;
#property (readonly) NSString *getGenre;
#property (readonly) NSString *getSongURL;
#property (readonly) NSString *getRating;
#property (readonly) NSString *getImage;
#property (readonly) BOOL isLocal;
-(void) setInfo:(NSString *) a: (NSString*) t: (NSString*) ab: (NSString*)g: (NSString*)sU: (NSString*)r: (NSString*) i: (BOOL) loc;
#end
#import "SongObject.h"
#implementation SongObject
-(id)init
{
if(self =[super init])
{
NSLog(#"Init songobject");
}
return self;
}
-(id) copyWithZone: (NSZone *) zone {
SongObject *newSong = [[SongObject allocWithZone:zone] init];
NSLog(#"_copy: %#", [newSong self]);
[newSong setInfo:[self getArtist] :[self getTitle] :[self getAlbum] :[self getGenre] :[self getSongURL] :[self getRating] :[self getImage] :[self isLocal]];
return(newSong);
}
-(void)dealloc
{
NSLog(#"Songobject deallocted from memory...");
[super dealloc];
}
-(void) setInfo:(NSString *) a: (NSString*) t: (NSString*) ab: (NSString*)g: (NSString*)sU: (NSString*)r: (NSString*) i: (BOOL) loc{
artist = a;
titel = t;
album = ab;
genre = g;
songUrl = sU;
rating = r;
image = i;
local = loc;
}
-(NSString*)getArtist
{
return artist;
}
-(NSString*)getTitle
{
return titel;
}
-(NSString*)getAlbum
{
return album;
}
-(NSString*)getGenre
{
return genre;
}
-(NSString*)getSongURL
{
return songUrl;
}
-(NSString*)getRating
{
return rating;
}
-(NSString*)getImage
{
return image;
}
-(BOOL)isLocal{
return local;
}
#end

That doesn't seem possible. Be careful, cause you're increasing the reference count twice. Once in the alloc, and again with the retain. What does selectedSong looks like? is it a property with automated retain?
Also, sometimes I cannot read the object in the debugger and I use NSLog. What do you see then?
What about overriding -dealloc. Did you try setting a breakpoint there?

I finally found the problem the SongObject class with the NSString variables was never retained. So the selectedSong was actually never released but the variables within the class it self.
Fixed it by using NSString alloc initWithString and then overriding the dealloc method and releasing them in there.

Related

How to record perfect loops in iOS and Xcode

I've been struggling with this for about a year now trying to pin down my problem and represent it for others to see.
I've been writing an app that depends on 'GarageBand' like recording. That is, I want to record the user for exactly 8 beats, and then I want them to be able to loop this. I am playing a metronome for the user at the same time (User would be wearing head phones hearing the metronome, recording into the mic on their device)
I can manage to turn on recording for about 4.8 seconds (.6*8 beats), and the timer says it ran for 4.8 seconds, however my audio recording is always a bit shorter than 4.8. It's like 4.78, or 4.71 which causes a the loop to go out of whack.
I've experimented with AVAudioRecorder,AudioQueue, and AudioUnits thinking one the latter methods might result in solving my problem.
I am using NSTimer to fire off every .6 seconds playing a short blip for the metronome. After 4 beats, the metronome timer's function, turns on the recorder metronnome which waits for 4.6 seconds the stops recording.
I'm using time intervals to time how long the metro runs (looks pretty tight at 4.800xxx) and comparing this to the duration of the audio file which is always different.
I wish I could attach my project, but I guess I'll just have to settle with attaching my header and implementation. To test you'll have to make a project with the following IB characteristics:
Record, Play, Stop buttons
Song/Track duration label
Timer duration label
Debug label
If you launch the app, then hit record, you are 'counted in' with 4 beats, then the recorder starts. Tap your finger on the desk until the recorder stops. After 8 more beats (12 in total) the recorder stops.
You can see in the displays that the recorded track is a little shorter than 4.8 seconds, and in some cases, a lot shorter, causing the audio to not loop properly.
Does anyone know what I can do to tighten this up? Thanks for reading.
Here's my code:
//
// ViewController.h
// speakagain
//
// Created by NOTHING on 2014-03-18.
//
#import <UIKit/UIKit.h>
#import <Foundation/Foundation.h>
#import "CoreAudio/CoreAudioTypes.h"
#import <AudioToolbox/AudioQueue.h>
#import <AudioToolbox/AudioFile.h>
#import <AVFoundation/AVFoundation.h>
#interface ViewController : UIViewController
{
IBOutlet UIButton *btnRecord;
IBOutlet UIButton *btnPlay;
IBOutlet UIButton *btnStop;
IBOutlet UILabel *debugLabel;
IBOutlet UILabel *timerDuration;
IBOutlet UILabel *songDuration;
//UILabel *labelDebug;
struct AQRecorderState {
AudioStreamBasicDescription mDataFormat;
AudioQueueRef mQueue;
AudioQueueBufferRef mBuffers[kNumberBuffers];
AudioFileID mAudioFile;
UInt32 bufferByteSize;
SInt64 mCurrentPacket;
bool mIsRunning; // 8
};
struct AQRecorderState aqData;
AVAudioPlayer *audioPlayer;
NSString *songName;
NSTimer *recordTimer;
NSTimer *metroTimer;
NSTimeInterval startTime, endTime, elapsedTime;
int inputBuffer;
int beatNumber;
}
#property (nonatomic, retain) IBOutlet UIButton *btnRecord;
#property (nonatomic, retain) IBOutlet UIButton *btnPlay;
#property (nonatomic, retain) IBOutlet UIButton *btnStop;
#property (nonatomic, retain) IBOutlet UILabel *debugLabel;
#property (nonatomic, retain) IBOutlet UILabel *timerDuration;
#property (nonatomic, retain) IBOutlet UILabel *songDuration;
- (IBAction) record;
- (IBAction) stop;
- (IBAction) play;
static void HandleInputBuffer (void *aqData,AudioQueueRef inAQ,AudioQueueBufferRef inBuffer,const AudioTimeStamp *inStartTime, UInt32 inNumPackets,const AudioStreamPacketDescription *inPacketDesc);
#end
Implementation:
//
// ViewController.m
// speakagain
//
// Created by NOTHING on 2014-03-18.
//
#import "ViewController.h"
#interface ViewController ()
#end
#implementation ViewController
#synthesize btnPlay, btnRecord,btnStop,songDuration, timerDuration, debugLabel;
- (void)viewDidLoad
{
debugLabel.text = #"";
songName =[[NSString alloc ]init];
//NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
//NSString *documentsDirectory = [paths objectAtIndex:0];
songName = #"TestingQueue.caf";
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
}
- (void)prepareAudioQueue
{
//struct AQRecorderState *pAqData;
inputBuffer=0;
aqData.mDataFormat.mFormatID = kAudioFormatLinearPCM;
aqData.mDataFormat.mSampleRate = 44100.0;
aqData.mDataFormat.mChannelsPerFrame = 1;
aqData.mDataFormat.mBitsPerChannel = 16;
aqData.mDataFormat.mBytesPerPacket =
aqData.mDataFormat.mBytesPerFrame = aqData.mDataFormat.mChannelsPerFrame * sizeof (SInt16);
aqData.mDataFormat.mFramesPerPacket = 1;
// AudioFileTypeID fileType = kAudioFileAIFFType;
AudioFileTypeID fileType = kAudioFileCAFType;
aqData.mDataFormat.mFormatFlags = kLinearPCMFormatFlagIsBigEndian| kLinearPCMFormatFlagIsSignedInteger| kLinearPCMFormatFlagIsPacked;
AudioQueueNewInput (&aqData.mDataFormat,HandleInputBuffer, &aqData,NULL, kCFRunLoopCommonModes, 0,&aqData.mQueue);
UInt32 dataFormatSize = sizeof (aqData.mDataFormat);
// in Mac OS X, instead use
// kAudioConverterCurrentInputStreamDescription
AudioQueueGetProperty (aqData.mQueue,kAudioQueueProperty_StreamDescription,&aqData.mDataFormat,&dataFormatSize);
//Verify
NSFileManager *fileManager = [NSFileManager defaultManager];
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *txtPath = [documentsDirectory stringByAppendingPathComponent:songName];
NSLog(#"INITIALIZING FILE");
if ([fileManager fileExistsAtPath:txtPath] == YES) {
NSLog(#"PREVIOUS FILE REMOVED");
[fileManager removeItemAtPath:txtPath error:nil];
}
const char *filePath = [txtPath UTF8String];
CFURLRef audioFileURL = CFURLCreateFromFileSystemRepresentation ( NULL,(const UInt8 *) filePath,strlen (filePath),false );
AudioFileCreateWithURL (audioFileURL,fileType,&aqData.mDataFormat, kAudioFileFlags_EraseFile,&aqData.mAudioFile );
DeriveBufferSize (aqData.mQueue,aqData.mDataFormat,0.5,&aqData.bufferByteSize);
for (int i = 0; i < kNumberBuffers; ++i)
{
AudioQueueAllocateBuffer (aqData.mQueue,aqData.bufferByteSize,&aqData.mBuffers[i]);
AudioQueueEnqueueBuffer (aqData.mQueue,aqData.mBuffers[i], 0,NULL );
}
}
- (void) metronomeFire
{
if(beatNumber < 5)
{
//count in time.
// just play the metro beep but don't start recording
debugLabel.text = #"count in (1,2,3,4)";
[self playSound];
}
if(beatNumber == 5)
{
//start recording
aqData.mCurrentPacket = 0;
aqData.mIsRunning = true;
startTime = [NSDate timeIntervalSinceReferenceDate];
recordTimer = [NSTimer scheduledTimerWithTimeInterval:4.8 target:self selector:#selector(killTimer) userInfo:nil repeats:NO];
AudioQueueStart (aqData.mQueue,NULL);
debugLabel.text = #"Recording for 8 beats (1,2,3,4 1,2,3,4)";
[self playSound];
}
else if (beatNumber < 12)
{ //play metronome from beats 6-16
[self playSound];
}
if(beatNumber == 12)
{
[metroTimer invalidate]; metroTimer = nil;
[self playSound];
}
beatNumber++;
}
- (IBAction) play
{
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *txtPath = [documentsDirectory stringByAppendingPathComponent:songName];
NSURL *url = [NSURL fileURLWithPath:[NSString stringWithFormat:#"%#",txtPath]];
if (audioPlayer)
{
[audioPlayer stop];
audioPlayer = nil;
}
NSError *error;
audioPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL:url error:&error];
if (audioPlayer == nil)
{
NSLog(#"%#",[error description]);
}
else
{
[audioPlayer play];
[audioPlayer setNumberOfLoops:-1];
}
}
- (void) killTimer
{
//this is the timer function. Runs once after 4.8 seconds.
[self stop];
}
- (IBAction) stop
{
if (audioPlayer)
{
[audioPlayer stop];
audioPlayer = nil;
}
else
{
if(metroTimer)
{
[metroTimer invalidate];metroTimer = nil;
}
//Stop the audio queue
AudioQueueStop (aqData.mQueue,true);
aqData.mIsRunning = false;
AudioQueueDispose (aqData.mQueue,true);
AudioFileClose (aqData.mAudioFile);
//Get elapsed time of timer
endTime = [NSDate timeIntervalSinceReferenceDate];
elapsedTime = endTime - startTime;
//Get elapsed time of audio file
NSArray *pathComponents = [NSArray arrayWithObjects:
[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject],
songName,
nil];
NSURL *audioFileURL = [NSURL fileURLWithPathComponents:pathComponents];
AVURLAsset* audioAsset = [AVURLAsset URLAssetWithURL:audioFileURL options:nil];
CMTime audioDuration = audioAsset.duration;
float audioDurationSeconds = CMTimeGetSeconds(audioDuration);
//Log values
NSLog(#"Track Duration: %f",audioDurationSeconds);
NSLog(#"Timer Duration: %.6f", elapsedTime);
//Show values on GUI too
songDuration.text = [NSString stringWithFormat: #"Track Duration: %f",audioDurationSeconds];
timerDuration.text = [NSString stringWithFormat:#"Timer Duration: %#",[NSString stringWithFormat: #"%.6f", elapsedTime]];
debugLabel.text = #"Why is the duration of the track less than the duration the timer ran?";
}
}
-(void) playSound
{
NSString *path = [[NSBundle mainBundle] pathForResource:#"blip2" ofType:#"aif"];
SystemSoundID soundID;
AudioServicesCreateSystemSoundID((__bridge CFURLRef)[NSURL fileURLWithPath:path], &soundID);
AudioServicesPlaySystemSound (soundID);
}
- (IBAction) record
{
[self prepareAudioQueue];
songDuration.text = #"";
timerDuration.text = #"";
//debugLabel.text = #"Please wait 12 beats (The first four are count in)";
//init beat number
beatNumber = 1;
//safe guard
if(aqData.mIsRunning)
{
AudioQueueStop (aqData.mQueue,true);
aqData.mIsRunning = false;
AudioQueueDispose (aqData.mQueue,true);
AudioFileClose (aqData.mAudioFile);
}
//start count in (metro will start recording)
//aqData.mCurrentPacket = 0;
//aqData.mIsRunning = true;
startTime = [NSDate timeIntervalSinceReferenceDate];
metroTimer = [NSTimer scheduledTimerWithTimeInterval:.6 target:self selector:#selector(metronomeFire) userInfo:nil repeats:YES];
//recordTimer = [NSTimer scheduledTimerWithTimeInterval:4.8 target:self selector:#selector(killTimer) userInfo:nil repeats:NO];
//AudioQueueStart (aqData.mQueue,NULL);
}
static void HandleInputBuffer (void *aqData,AudioQueueRef inAQ,AudioQueueBufferRef inBuffer,const AudioTimeStamp *inStartTime,UInt32 inNumPackets,const AudioStreamPacketDescription *inPacketDesc)
{
//boiler plate
NSLog(#"HandleInputBuffer");
struct AQRecorderState *pAqData = (struct AQRecorderState *) aqData;
if (inNumPackets == 0 && pAqData->mDataFormat.mBytesPerPacket != 0)
inNumPackets = inBuffer->mAudioDataByteSize / pAqData->mDataFormat.mBytesPerPacket;
if (AudioFileWritePackets (pAqData->mAudioFile,false,inBuffer->mAudioDataByteSize,inPacketDesc,pAqData->mCurrentPacket,&inNumPackets,inBuffer->mAudioData) == noErr)
{
pAqData->mCurrentPacket += inNumPackets;
}
if (pAqData->mIsRunning == 0)
return;
AudioQueueEnqueueBuffer (pAqData->mQueue,inBuffer,0,NULL);
}
void DeriveBufferSize(AudioQueueRef audioQueue,AudioStreamBasicDescription ASBDescription,Float64 seconds,UInt32 *outBufferSize)
{
//boiler plate
static const int maxBufferSize = 0x50000;
int maxPacketSize = ASBDescription.mBytesPerPacket;
if(maxPacketSize == 0)
{
UInt32 maxVBRPacketSize = sizeof(maxPacketSize);
AudioQueueGetProperty(audioQueue, kAudioQueueProperty_MaximumOutputPacketSize, &maxPacketSize, &maxVBRPacketSize);
NSLog(#"max buffer = %d",maxPacketSize);
}
Float64 numBytesForTime = ASBDescription.mSampleRate * maxPacketSize * seconds;
*outBufferSize = (UInt32)(numBytesForTime < maxBufferSize ? numBytesForTime : maxBufferSize);
}
OSStatus SetMagicCookieForFile (AudioQueueRef inQueue, AudioFileID inFile)
{
//boiler plate
OSStatus result = noErr;
UInt32 cookieSize;
if (AudioQueueGetPropertySize (inQueue,kAudioQueueProperty_MagicCookie,&cookieSize) == noErr)
{
char* magicCookie =(char *) malloc (cookieSize);
if (AudioQueueGetProperty (inQueue,kAudioQueueProperty_MagicCookie,magicCookie,&cookieSize) == noErr)
{
result = AudioFileSetProperty (inFile,kAudioFilePropertyMagicCookieData,cookieSize,magicCookie);
}
free (magicCookie);
}
return result;
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
#end
This is a big topic so I doubt you'll get an answer big enough to re-architect the code that you've provided. However, I can give you links that will supply the vast majority of what you require.
First thing is NSTimer would never work due to synchronisation issues. Also, forget AudioQueue and AVAudioRecorder. Only AudioUnit is low level enough for your needs.
Have a look at my answer here:
iOS Stream Audio from one iOS Device to Another
But the true goldmine - and knowledge that you will need to be intimately familiar with - is Tasty Pixel's blog. Tasty Pixel being the vendor of Loopy HD, but also someone that is kind enough to share some pretty in depth knowledge.
See:
A simple, fast circular buffer implementation for audio processing
Developing Loopy, Part 2: Implementation
and
Using RemoteIO audio unit
Finally, make sure you are familiar with packets, frames, samples, etc. Everything needs to sync perfectly.

CoreData: Error by decode data from Context/Store NSData -> NSArray

i'm new in iOS-Development area and trying now to update an existing App to iOS 6.1 from iOS4.
get Data from Store to show in NewsPageView : UIViewController
NewsPageView.m
#import "NewsPageView.h"
#interface NewsPageView ()
#end
#implementation NewsPageView
#synthesize newsDetailsView,
newsTableView,
newsHeaderText
;
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view.
/*
* Get managedObjectContext and List of News over AppDelegate
*/
AppDelegate* appDelegate = [UIApplication sharedApplication].delegate;
//Setting self.managedObjectContext
self.managedObjectContext = appDelegate.managedObjectContext;
// Fetching Records from the data base to show in the table
self.listOfNews = [[appDelegate getDataFromStore:self]copy];
//
NSLog(#"Data from Store in NewsPageView: %#",self.listOfNews.description);
}
try to set/write data into Context
-(void) setDataToStore
{
NSLog(#"Trying to write News in Store");
News *newNews = [NSEntityDescription insertNewObjectForEntityForName:#"News" inManagedObjectContext:self.managedObjectContext];
newNews.newsId = [[NSNumber alloc]initWithInt:508];
newNews.title = #"Some Title";
newNews.content = #"Some content";
newNews.detailsUrl = #"www.someURL.de";
newNews.date = [[NSDate alloc]init];
newNews.dateTs = [[NSNumber alloc]initWithInt:138114787];
newNews.primaryCat = [[NSNumber alloc]initWithInt:0];
//make Categorien...
NewsCategorien *cat1 = [NSEntityDescription insertNewObjectForEntityForName:#"NewsCategorien" inManagedObjectContext:self.managedObjectContext];
cat1.catId = [[NSNumber alloc]initWithInt:1];
cat1.name = #"Windows";
cat1.news = newNews;
NewsCategorien *cat2 = [NSEntityDescription insertNewObjectForEntityForName:#"NewsCategorien" inManagedObjectContext:self.managedObjectContext];
cat2.catId = [[NSNumber alloc]initWithInt:2];
cat2.name = #"Linux";
cat2.news = newNews;
NewsCategorien *cat3 = [NSEntityDescription insertNewObjectForEntityForName:#"NewsCategorien" inManagedObjectContext:self.managedObjectContext];
cat3.catId = [[NSNumber alloc]initWithInt:3];
cat3.name = #"Apple";
cat3.news = newNews;
NewsCategorien *cat5 = [NSEntityDescription insertNewObjectForEntityForName:#"NewsCategorien" inManagedObjectContext:self.managedObjectContext];
cat5.catId = [[NSNumber alloc]initWithInt:5];
cat5.name = #"Smartphone";
cat5.news = newNews;
newNews.isNews = [NSNumber numberWithBool:YES];
NSArray *catListe = [NSArray arrayWithObjects:cat1,cat2,cat3,cat5, nil];
// //saving cat by converting Cat. objects
// newNews.categories = catListe;
NSError *error;
if (![self.managedObjectContext save:&error]) {
NSLog(#"Whoops, couldn't save: %#", [error localizedDescription]);
}
NSLog(#"Saving ok!");
}
try to get Data from Context
- (NSArray *)getDataFromStore:(id)sender
{
// initializing NSFetchRequest
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
NSArray *fetchedData;
//get Data für NewsTable View
if([sender isKindOfClass:[NewsPageView class]]){
//Setting Entity to be Queried
fetchRequest.entity = [NSEntityDescription entityForName:#"News" inManagedObjectContext:self.managedObjectContext];
NSError* error;
//Point of Error by debugging!!!
//return list of News
fetchedData = [self.managedObjectContext executeFetchRequest:fetchRequest error:&error];
}
//print fetched Data
for (News *news in fetchedData) {
NSLog(#"News:%#", news.description);
}
// Returning Fetched News
return fetchedData;
}
Classes
News.h
#import <Foundation/Foundation.h>
#import <CoreData/CoreData.h>
#class NewsCategorien;
#interface News : NSManagedObject <NSCoding>
#property (nonatomic, retain) id categories;
#property (nonatomic, retain) NSString * content;
#property (nonatomic, retain) NSDate * date;
#property (nonatomic, retain) NSNumber * dateTs;
#property (nonatomic, retain) NSString * detailsUrl;
#property (nonatomic, retain) NSNumber * isNews;
#property (nonatomic, retain) NSNumber * newsId;
#property (nonatomic, retain) NSNumber * primaryCat;
#property (nonatomic, retain) NSString * title;
#property (nonatomic, retain) NSSet *categorie;
//have to be implement...
//to work with NSKeyedArchiver by serialising Objects
- (void)encodeWithCoder:(NSCoder *)aCoder;
//to work with NSKeyedUnarchiver by deserialising Objects
- (id)initWithCoder:(NSCoder *)aDecoder;
#end
#interface News (CoreDataGeneratedAccessors)
- (void)addCategorieObject:(NewsCategorien *)value;
- (void)removeCategorieObject:(NewsCategorien *)value;
- (void)addCategorie:(NSSet *)values;
- (void)removeCategorie:(NSSet *)values;
#end
/*
* News Transformer NSArray -> NSData and reverse
* Model: News should have Attribut type of Transformable and have name NewsTrasformer
*/
#interface NewsTransformer : NSValueTransformer
#end
News.m
#import "News.h"
#import "NewsCategorien.h"
#implementation News
#dynamic categories;
#dynamic content;
#dynamic date;
#dynamic dateTs;
#dynamic detailsUrl;
#dynamic isNews;
#dynamic newsId;
#dynamic primaryCat;
#dynamic title;
#dynamic categorie;
//tell the archiver how to transform the serialized representation into a new object -> deserialize Objects!
- (id)initWithCoder:(NSCoder *)decoder {
if (self = [super init]) {
self.categories = [decoder decodeObjectForKey:#"categories"];
self.content = [decoder decodeObjectForKey:#"content"];
self.date = [decoder decodeObjectForKey:#"date"];
self.dateTs = [decoder decodeObjectForKey:#"dateTs"];
self.detailsUrl = [decoder decodeObjectForKey:#"detailsUrl"];
self.isNews = [decoder decodeObjectForKey:#"isNews"];
self.newsId = [decoder decodeObjectForKey:#"newsId"];
self.primaryCat = [decoder decodeObjectForKey:#"primaryCat"];
self.title = [decoder decodeObjectForKey:#"title"];
self.categorie = [decoder decodeObjectForKey:#"categorie"];
}
NSLog(#"<<<< ---- Deserialize Object News (Init With Code) --->");
return self;
}
//tell the archiver how to serialize your object into bytes -> serialize Objects!
- (void)encodeWithCoder:(NSCoder *)encoder {
[encoder encodeObject:self.categories forKey:#"categories"];
[encoder encodeObject:self.content forKey:#"content"];
[encoder encodeObject:self.date forKey:#"date"];
[encoder encodeObject:self.dateTs forKey:#"dateTs"];
[encoder encodeObject:self.detailsUrl forKey:#"detailsUrl"];
[encoder encodeObject:self.isNews forKey:#"isNews"];
[encoder encodeObject:self.newsId forKey:#"newsId"];
[encoder encodeObject:self.primaryCat forKey:#"primaryCat"];
[encoder encodeObject:self.title forKey:#"title"];
[encoder encodeObject:self.categorie forKey:#"categorie"];
NSLog(#"<<<< ---- Serialize Object News (encode With Coder) --->");
}
#end
//
#implementation NewsTransformer
//Return the Class for Forwarding Transformation
+ (Class)transformedValueClass
{
return [NSArray class];
}
+ (BOOL)allowsReverseTransformation
{
return YES;
}
// converts the NSArray into NSData using NSKeyedArchiver
- (id)transformedValue:(id)value
{
NSLog(#"Transformer: NSArray -> NSData");
return [NSKeyedArchiver archivedDataWithRootObject:value];
}
// by default raises an exception if +allowsReverseTransformation returns NO and otherwise invokes transformedValue:
//converts NSData to an NSArray using NSKeyedUnarchiver
- (id)reverseTransformedValue:(id)value
{
NSLog(#"Transformer: NSData -> NSArray");
return [NSKeyedUnarchiver unarchiveObjectWithData:value];
}
#end
NewsCategorien.h
#import <Foundation/Foundation.h>
#import <CoreData/CoreData.h>
#class News;
#interface NewsCategorien : NSManagedObject <NSCoding>
#property (nonatomic, retain) NSNumber * catId;
#property (nonatomic, retain) NSString * name;
#property (nonatomic, retain) News *news;
//for serializing of objects have to be implement...
- (void)encodeWithCoder:(NSCoder *)aCoder;
//for serializing of objects have to be implement...
- (id)initWithCoder:(NSCoder *)aDecoder;
#end
NewsCategorien.m
#import "NewsCategorien.h"
#import "News.h"
#implementation NewsCategorien
#dynamic catId;
#dynamic name;
#dynamic news;
- (id)initWithCoder:(NSCoder *)decoder {
if (self = [super init]) {
self.catId = [decoder decodeObjectForKey:#"catId"];
self.name = [decoder decodeObjectForKey:#"name"];
self.news = [decoder decodeObjectForKey:#"news"];
}
NSLog(#"<<<< ---- Deserialize Object Categorie ---> : %#",self.description);
return self;
}
- (void)encodeWithCoder:(NSCoder *)encoder {
[encoder encodeObject:self.catId forKey:#"catId"];
[encoder encodeObject:self.name forKey:#"name"];
[encoder encodeObject:self.news forKey:#"news"];
NSLog(#"<<<< ---- Serialize Object Categorie ---> %#",self.description);
}
#end
Model
News
Attribute: categorien Type: Transformable Name: NewsTransformer
Relationchip one-to-more
categorien Des. NewsCategorien Inverse news
Categorien
Att. catId String
Att. name Interger16
My problem:
1. writing data to the context - OK
2.when i'm trying to get data from the context(NSData->NSArray) i get following error:
Error
CoreData: error: Failed to call designated initializer on NSManagedObject class 'NewsCategorien'
2013-11-20 16:03:19.204 securityNews[19458:c07] -[NewsCategorien setCatId:]: unrecognized selector sent to instance 0x8173740
2013-11-20 16:03:19.205 securityNews[19458:c07] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[NewsCategorien setCatId:]: unrecognized selector sent to instance 0x8173740'
any idea what i doing wrong??
The first error is almost certainly due to your implementation of initWithCoder:, specifically this line:
if (self = [super init]) {
You can't create a managed object using init. You must use the designated initializer initWithEntity:insertIntoManagedObjectContext:. Or you can use NSEntityDescription's method insertNewObjectForEntityForName:inManagedObjectContext:. But using init is right out, and doing so will cause a Failed to call designated initializer error.
This means that your initWithCoder needs to be able to find a managed object context. How you do that depends on your app's structure and where you are creating contexts. If your app delegate has a context object and that's the one you want to use, you could look it up from there. If it's some other context, you'll have to get it from somewhere else. You have a couple of versions of initWithCoder and they both have this problem.
The second error is a side-effect of the first error. In initWithCoder you do this:
if (self = [super init]) {
self.catId = [decoder decodeObjectForKey:#"catId"];
....
But since [super init] doesn't work, you're getting back a bogus object that doesn't know what catId is. Then you try to set catId and it fails. Fix the first error and the second error will disappear.

Not accessing value from Object

I have a NSObject called GettingHere which has a NSString *content.
I then have a UIViewController on which I create a button programatically as follows (this button working as intended):
byAirButton = [UIButton buttonWithType:UIButtonTypeCustom];
byAirButton.tag = 1;
byAirButton.frame = CGRectMake(25, 140, 280.f, 40.f);
UIImage *airButton = [UIImage imageNamed:#"gettingHereByAirButton.png"];
[byAirButton setBackgroundImage:airButton forState:UIControlStateNormal];
[self.view addSubview:byAirButton];
[byAirButton addTarget:self action:#selector(byAirButtonClicked) forControlEvents:UIControlEventTouchUpInside];
For the action:#selector(byAirButtonClicked), I do the following. gettingHere is an instance of the GettingHere object.
- (void) byAirButtonClicked
{
gettingHere.content = #"This is how to get here by Air";
NSLog(#"Content: %#", gettingHere.content);
[self performSegueWithIdentifier:#"gettingHereSegue" sender:self];
}
The idea is to set the content for my GettingHere object and then just call that from the next view (GettingHereViewController) when the user clicks the byAirButton.
This NSLog shows that content is being set.
In my prepareForSegue, I do the following:
- (void) prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([segue.identifier isEqualToString:#"gettingHereSegue"])
{
NSLog(#"Content to be passed: %#", gettingHere.content);
GettingHereViewController *vc = (GettingHereViewController *)segue.destinationViewController;
vc.gettingHere.content = gettingHere.content;
}
}
The segue works fine, but the NSLog shows my gettingHere object values as being (null).
Can anyone tell me where I am going wrong please? I have stepped through it several times but can't figure out where I am going wrong.
EDIT: Here is how I instantiate the GettingHere Object.
In the SubNavViewController.h
#import "GettingHereContent.h"
#interface SubNavViewController : UIViewController
#property GettingHereContent *gettingHere;
In the SubNavViewController.m
#import "SubNavViewController.h"
#import "GettingHereViewController.h"
#import "GettingHereContent.h"
#interface SubNavViewController ()
#end
#implementation SubNavViewController
#synthesize gettingHere;
And here is how I create the GettingHere Object:
GettingHere.h
#import <Foundation/Foundation.h>
#interface GettingHereContent : NSObject
#property (nonatomic, strong) NSString *content;
#end
GettingHere.m
#import "GettingHereContent.h"
#implementation GettingHereContent
#synthesize content;
#end
You never alloc init your gettingHere property. Try this in your init method of your VC
gettingHere = [[GettingHereContent alloc] init];
Also don't forget to release it: answer from here: alloc + init with synthesized property - does it cause retain count to increase by two?
#interface Foo : Bar {
SomeClass* bla;
}
#property (nonatomic, retain) SomeClass* bla;
#end
#implementation Foo
#synthesize bla;
-(id)init {
...
bla = [[SomeClass alloc] init];
...
}
-(void)dealloc {
[bla release];
...
[super dealloc];
}

Singleton class for displaying iAds for iPhone

I have written a Singleton Class for managing iAds.The iAds pop up after 5 seconds of the user inactivity. The idleTimerExceeded call generate a notification to show the iAd. This code works fine for my requirements but since I am new to iOS development, my application sometimes hangs unexpectedly after integrating this code. This code results in lots of warnings etc. I would like to optimize my code in terms of memory and performance.
I would be very thankful for your kind suggestions and reviews.
Below is my code:
iAdSingleton.h
#import <Foundation/Foundation.h>
#import "AppDelegate.h"
#import "iAd/iAd.h"
#interface iAdSingleton : UIViewController<ADBannerViewDelegate> {
ADBannerView *adView;
UIViewController *displayVC;
NSTimer *idleTimer;
BOOL isItFirstTime;
}
#property (nonatomic, retain) ADBannerView *adView;
#property (nonatomic, retain) UIViewController *displayVC;
#property (nonatomic) BOOL isItFirstTime;
+ (id) shareAdSingleton;
- (void) resetIdleTimer;
- (void) idleTimerExceeded;
#end
iAdSingleton.m
#import "iAdSingleton.h"
#implementation iAdSingleton
static iAdSingleton* _sharedAdSingleton = nil;
BOOL bannerVisible = NO;
BOOL controlAccessBannerVisibility = NO;
#synthesize adView, displayVC;
#synthesize isItFirstTime;
#define kMaxIdleTimeSeconds 5.0
+(id)sharedAdSingleton
{
#synchronized(self)
{
if(!_sharedAdSingleton)
_sharedAdSingleton = [[self alloc] init];
return _sharedAdSingleton;
}
return nil;
}
+(id)alloc
{
#synchronized([iAdSingleton class])
{
NSAssert(_sharedAdSingleton == nil, #"Attempted to allocate a second instance of a singleton.");
_sharedAdSingleton = [super alloc];
return _sharedAdSingleton;
}
return nil;
}
-(id)init
{
self = [super init];
if (self != nil) {
/* Initialize The Parameters Over Here */
//adView = [[ADBannerView alloc] initWithFrame:CGRectMake(0, 480, 0, 0)];
adView = [[ADBannerView alloc] init];
adView.currentContentSizeIdentifier = ADBannerContentSizeIdentifierPortrait;
self.adView.delegate=self;
[self resetIdleTimer];
}
return self;
}
-(void)dealloc
{
displayVC = nil;
if (adView) {
[adView removeFromSuperview]; //Remove ad view from superview
[adView setDelegate:nil];
adView = nil;
}
[super dealloc];
}
-(UIViewController *)viewControllerForPresentingModalView
{
return displayVC;
}
- (void)bannerViewDidLoadAd:(ADBannerView *)banner
{
banner.hidden = NO;
if(!bannerVisible){
NSLog(#"Banner Changes 1 - Purpose: Visibility");
// [UIView beginAnimations:#"bannerAppear" context:NULL];
// banner.frame = CGRectOffset(banner.frame, 0, -100);
// [UIView commitAnimations];
bannerVisible = YES;
controlAccessBannerVisibility = YES;
}
}
- (void)bannerView:(ADBannerView *)banner didFailToReceiveAdWithError:(NSError *)error
{
//NSLog(#"Unable to receive Ad.");
NSLog(#"Banner Changes 2 - Purpose: Unable to Receive Ad.");
banner.hidden = YES;
if(bannerVisible){
[UIView beginAnimations:#"bannerDisappear" context:NULL];
banner.frame = CGRectOffset(banner.frame, 0, 100);
[UIView commitAnimations];
bannerVisible = NO;
}
}
- (BOOL) bannerViewActionShouldBegin:(ADBannerView *)banner willLeaveApplication:(BOOL)willLeave
{
NSLog(#"Pause anything necessary");
return YES;
}
- (void) bannerViewActionDidFinish:(ADBannerView *)banner
{
NSLog(#"We now resume to normal operations");
}
- (void)resetIdleTimer {
if (!idleTimer) {
idleTimer = [[NSTimer scheduledTimerWithTimeInterval:kMaxIdleTimeSeconds
target:self
selector:#selector(idleTimerExceeded)
userInfo:nil
repeats:NO] retain];
}
else {
if (fabs([idleTimer.fireDate timeIntervalSinceNow]) < kMaxIdleTimeSeconds-1.0) {
[idleTimer setFireDate:[NSDate dateWithTimeIntervalSinceNow:kMaxIdleTimeSeconds]];
/*
Notification: HideAd
*/
NSLog(#"Notification Generated For HideAd");
[[NSNotificationCenter defaultCenter] postNotificationName:#"HideAdBanner" object:nil userInfo:nil];
}
}
}
- (void)idleTimerExceeded {
AppDelegate *appDel = (AppDelegate *)[[UIApplication sharedApplication] delegate];
if (appDel.adVisible == NO) {
NSLog(#"Notification Generated For ShowAd");
/*
Notification: ShowAd
*/
if (controlAccessBannerVisibility == YES) {
[[NSNotificationCenter defaultCenter] postNotificationName:#"ShowAdBanner" object:nil userInfo:nil];
}
}
}
#end
This is what you need. This code is thread safe as well as will not have any memory issue and warnings.
+ (iAdSingleton *) sharedInstance
{
static dispatch_once_t onceToken;
static iAdSingleton * __sharedInstance = nil;
dispatch_once(&onceToken, ^{
__sharedInstance = [[self alloc] init];
});
return __sharedInstance;
}

NSMutableArray Add/Remove Objects (Inherited File)

Okay, so I'm pretty new to xcode but I cannot find something specific to this issue anywhere. So I declare the array and instantiate it in the following files:
//xmlToUrl.h
#import <Foundation/Foundation.h>
#interface xmlToUrl : NSObject {
NSMutableArray *field;
NSMutableArray *name;
}
#property(nonatomic, retain)NSMutableArray *field;
#property(nonatomic, retain)NSMutableArray *name;
#end
and
//xmlToUrl.m
#import "xmlToUrl.h"
#implementation xmlToUrl
#synthesize field;
#synthesize name;
-(void)dealloc
{
[field release];
[name release];
[super dealloc];
}
#end
So this is where I am confused. I don't know how to correctly "alloc" or "init" the mutable arrays, nor how to handle the add/remove operations from another file which inherits xmlToUrl.h.
The code (in the other file) as I have it now just prints null. Its listed below. What am I doing wrong?!?
//nodeContent is just a NSMutableString
[xmlToUrlObject.name addObject:nodeContent];
NSLog(#"xml Name = %#", xmlToUrlObject.name);
//I omitted all the operational code here but if I NSLog nodeContent it prints the correct values
[xmlToUrlObject.field addObject:nodeContent];
NSLog(#"xml Field = %#", xmlToUrlObject.field);
You need an init function in your implementation file, it would look similar to the following
-(id) init
{
self = [super init];
if (self) {
field = [[NSMutableArray alloc] init];
name = [[NSMutableArray alloc] init];
}
return self;
}
Then whenever you create an instance of your xmlToUrl class via [[xmlToUrl alloc] init] you will have an instance of your class that has already initialized your two NSMutableArrays

Resources