This question already has answers here:
Closed 11 years ago.
Possible Duplicate:
How do I use NSTimer
Decrement Issue
I'm really struggling to get rid of the following warning:
Incorrect decrement of the reference count of an object that is at this point not owned by the caller.
The code compiles fine and the app seems to work fine. Basically I am trying to create an object of a class to play a short audio clip when the button is pressed. I've created a class to play the file and the objects are passed the files name as a string.
Here is the code:
- (IBAction) playKick
{
PlayAudio *thisPlayAudio= [[[PlayAudio alloc] init] playFile:(#"RockSnare")];
[thisPlayAudio release];
}
I've read the other posts and any help would be much appreciated!
I'd have to see the class definition for PlayAudio, but it's doubtful the playFile method returns its PlayAudio instance. You probably want this:
PlayAudio *thisPlayAudio = [[PlayAudio alloc] init];
[thisPlayAudio playFile:(#"RockSnare")];
[thisPlayAudio release];
Maybe this would help:
- (IBAction) playKick {
PlayAudio *thisPlayAudio= [[PlayAudio alloc] init];
[thisPlayAudio playFile:(#"RockSnare")];
[thisPlayAudio release];
}
This finishes creating the object and assigns it to thisPlayAudio, then plays the audio. What you have sets thisPlayAudio to the result of the playFile call.
What is the return type of the playFile: method? Are you sure it returns the same object you call it on?
Maybe your code should be:
PlayAudio *thisPlayAudio= [[PlayAudio alloc] init];
[thisPlaysAudio playFile:#"RockSnare"];
[thisPlaysAudio release];
or even
[[[[PlayAudio alloc] init] autorelease] playFile:(#"RockSnare")];
You are trying to immediately release object after creating. Probably, you also doing something wrong in playFile method. And your player won't play any file since you create and delete it in one scope. Try this:
PlayAudio *thisPlayAudio = nil;
- (IBAction) playKick {
if (thisPlayAudio){
[thisPlayAudio release]; thisPlayAudio = nil;
}
thisPlayAudio= [[PlayAudio alloc] init] autorelease];
[thisPlayAudio playFile:(#"RockSnare")];
}
Related
I am very new to objective c and OpenEars so please forgive me if I have some messy code and if I am lost in very simple problem.
Anyhow, I have two controllers in this application. The first being the default ViewController and the second one being a new one that I made called ReplyManagerController.
The code in the ViewController basically uses the one in the tutorial with some (maybe more some) changes.
EDIT:
The app is supposed to be a basic app where a user says something and the app replies.
But the original problem was that I could not get the string to display or TTS to work when my ViewController got it's string from another class/controller.
The answer in my below mentions that it was probably because my other class was calling my ViewController without the self.fliteController initialized.
How would I initialize the ViewController with self.fliteController initialized?
ViewController.m
- (void) pocketsphinxDidReceiveHypothesis:(NSString *)hypothesis recognitionScore:(NSString *)recognitionScore utteranceID:(NSString *)utteranceID {
NSString *strResult = hypothesis; //speech to text to string
ReplyManager* replyObject = [[ReplyManager alloc] init];
[replyObject speechResult:(NSString*)strResult viewController:self];
}
- (void) getReply:(NSString*)replyStr{
[self.fliteController say:replyStr withVoice:self.slt];
[self updateText:replyStr];
}
- (IBAction)updateText:(NSString*)replyStr{
labelOne.text = replyStr;
labelOne.adjustsFontSizeToFitWidth = YES;
labelOne.minimumFontSize = 0;
}
Any help will be great! Thanks!
ReplyManager.m
- (void) speechResult:(NSString*)strResult {
NSString *replystr;
NSString *greetings = #"Hi!";
NSString *sorry = #"Sorry I didn't catch that?";
ViewController* getReply = [[ViewController alloc] init];
if ([strResult isEqualToString:#"HELLO"])
{
replystr = greetings;
[getReply getReply:(NSString*)replystr];
}
else
{
replystr = sorry;
[getReply getReply:(NSString*)replystr];
}
}
EDIT 2:
viewDidLoad Method
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
self.fliteController = [[OEFliteController alloc] init];
self.slt = [[Slt alloc] init];
self.openEarsEventsObserver = [[OEEventsObserver alloc] init];
[self.openEarsEventsObserver setDelegate:self];
}
ViewController* getReply = [[ViewController alloc] init];
Here you init a new ViewController which does not have self.fliteController defined most likely. You need to reuse previos controller, for example like this:
[replyObject speechResult:(NSString*)strResult viewController:self];
So you can use already initialized viewController later. Overall it is better to initialize objects like viewController or replyController beforehand, not inside callback methods.
It sounds like a timing issue where you're trying to use fliteController before it's been initialized.
In your ViewController class, where do you assign a value to the fliteController property? In an initializer? -(void)viewDidLoad?
In ReplyManagerController add:
ViewController* getReply = [[ViewController alloc] init];
// Add these lines
NSLog(getReply.fliteController); // Is this nil?
[getReply.view layoutIfNeeded];
NSLog(getReply.fliteController); // Is it still nil?
Does the above fix the problem? If so, you're probably initializing fliteController in -(void)viewDidLoad. What's the result of the two NSLog statements?
I want to create a new UILocalNotification every time I enter a certain method. I would assume this would have to be done by reading from an array or something along this line but I cannot figure it out. How do I do such a thing dynamically without hardcoding something like the following:
-(void) createNotification
{
UILocalNotification *notification1;
}
Now I would like to be able to create notification2, notification3, etc etc each time I enter createNotification. For the specific reason that then I can cancel the appropriate notification without cancelling them all.
The following is what I have attempted, perhaps Im way off... maybe not. Either way if someone could provide some input, would be appreciated. Thanks!
-(void) AddNewNotification
{
UILocalNotification *newNotification = [[UILocalNotification alloc] init];
//[notificationArray addObject:newNotification withKey:#"notificationN"];
notificationArray= [[NSMutableArray alloc] init];
[notificationArray addObject:[[NSMutableDictionary alloc]
initWithObjectsAndKeys:newNotification,#"theNotification",nil]];
}
You are almost there: using an array is certainly the right thing to do! The only problem is that you keep creating a new instance of the array every time you go through your AddNewNotification method. You should make notificationArray an instance variable, and move its initialization code notificationArray= [[NSMutableArray alloc] init]; to the designated initializer of the class where notificationArray is declared.
If you would like to give each notification that you insert an individual key by which you can find it later, use NSMutableDictionary instead of NSMutableArray. Re-write the AddNewNotification method as follows:
-(void) addNewNotificationWithKey:(NSString*)key {
UILocalNotification *newNotification = [[UILocalNotification alloc] init];
[notificationDict setObject:[[NSMutableDictionary alloc]
initWithObjectsAndKeys:newNotification,#"theNotification",nil]
forKey:key];
}
When you call the addNewNotificationWithKey: method, you'd be able to provide a key for the newly added notification, for example
[self addNewNotificationWithKey:#"notification1"];
[self addNewNotificationWithKey:#"notification2"];
and so on.
I'm still new to Objective-C so I'm having a hard time with this. In my AppController, When a user clicks on one of the ads in my app, then closes the ad and returns to my app, I would like to destroy and recreate the ad (Long story as to why). For some reason though, my code isn't working. There are no errors or warnings, but it doesn't do what I intended it to do. This is what my code looks like:
#import "MoPubManager.h"
......
- (void)applicationWillEnterForeground:(UIApplication *)application
{
MoPubManager *obj = [[MoPubManager alloc] init];
if( obj.adView ) {
[[MoPubManager sharedManager] destroyBanner];
}
[obj.adView refreshAd];
}
_adView, destroy banner, and refresh ad are both in the MoPubManager file, so as you can see I imported the file and turned MoPubManager into an object. (obj.adView was originally just _adView in MoPubManager.h, but I had to switch it to obj.adView to avoid warnings.) I may just be using the wrong calls, I would post the MoPubManager.mm file where the calls originally are but its a full page or two
In the line:
MoPubManager *obj = [[MoPubManager alloc] init];
You are creating a new instance of the MoPubManager class.
Next you are checking whether the adView property of that newly instantiated class is not nil. Unless adView gets populated in the init method of MoPubManager, this will always be nil, so the destroyBanner method will not be called.
However, the destroyBanner method is being called on a sharedManager... indicating a singleton pattern in use. Therefore you should not be creating a new instance as this goes against the reason for using a singleton. (You only ever have one instance of a class when using a singleton - see this for more info)
Without seeing more code, it seems that you should be calling something like:
if( [MoPubManager sharedManager].adView ) {
[[MoPubManager sharedManager] destroyBanner];
}
[[MoPubManager sharedManager].adView refreshAd];
First, what subclass is MoPubManager... It compiles fine? The problem here seems to be that you are creating a new MoPubManager instance, but you are using a singleton to destroy it, and they don't have the same reference. You should use something diferent like:
MoPubManager *obj = [[MoPubManager alloc] init];
if( [MoPubManager sharedManager].adView ) {
[[MoPubManager sharedManager] destroyBanner];
}
[[MoPubManager sharedManager].adView refreshAd];
You are not using correctly the singleton pattern.
try this , maybe will help you
- (void)applicationWillEnterForeground:(UIApplication *)application
{
MoPubManager *obj = [MoPubManager sharedManager];
if( obj.adView ) {
[obj destroyBanner];
}
[obj.adView refreshAd];
}
I have a memory leak in my iPhone app. I added Google AdMob to my app using sample code downloaded from Google. However, I was having a hard time getting it into testing mode so I added an extra variable as follows:
GADRequest *r = [[GADRequest alloc] init];
r.testing = YES;
[bannerView_ loadRequest:r];
I found the memory leak using Instruments. Instruments does not lead me to this line of code, it just dumps me in the main.m file. However, when I comment out the code relating to AdMob the leak goes away and I know enough to see that I haven't taken care of releasing this new variable. I just don't know exactly how I should set about releasing it. The variable r is not addressed in the header file so this is all the code that deals with it.
I tried adding:
- (void)dealloc {
[r release];
....
}
but that caused a build error saying "'r' undeclared". That's weird because it looks to me like I'm declaring r in the first quoted line above but I guess that's wrong. Any help would be much appreciated. I really have tried to educate myself about memory leaks but I still find them very confusing.
Just add [r release]; right below the code:
GADRequest *r = [[GADRequest alloc] init];
r.testing = YES;
[bannerView_ loadRequest:r];
[r release];
The variable r is declared only in that section of your code, so that's where it should be released. The point of releasing is to get rid of it as soon as you no longer need it, so the above should work perfectly for you.
If your r is locally declared (as it seems, judging from your snippet), then it cannot be accessed from outside its scope (here: the method it was declared in).
You either need to make it accessible within your class instance by declaring it an ivar.
Declaring it an ivar would look like this:
#interface YourClass : SuperClass {
GADRequest *request;
}
//...
#end
You then change your code to this:
request = [[GADRequest alloc] init];
request.testing = YES;
[bannerView_ loadRequest:request];
Also don't forget to release it in dealloc:
- (void)dealloc {
[request release];
//...
}
However this is not what you want in this situation (I've just included it to clarify why you get the warning about r not being declared).
You (most likely) won't need request any second time after your snippet has run, thus storing it in an ivar will only needlessly occupy RAM and add unwantd complexity to your class. Stuff you only need at the immediate time after its creation should be taken care of (released) accordingly, that is within the very same scope.
What you'll actually want to do is simply (auto)release it, properly taking care of it.
Keep in mind though that your loadRequest: will need to take care of retaining r for as long as it needs it. Apple's implementation does this, of course. But you might want to write a similar method on your own one day, so keep this in mind then.
GADRequest *r = [[GADRequest alloc] init];
r.testing = YES;
[bannerView_ loadRequest:r];
[r release]; //or: [r autorelease];
OP here. Thanks for all the detailed and thoughtful responses. This has definitely helped get a better handle on memory management. I did exactly as recommended, adding [r release]; right below the posted code. However, I still have a leak. I have isolated it to a single line of code. The following leaks:
GADRequest *r = [[GADRequest alloc] init];
r.testing = YES;
[bannerView_ loadRequest:r];
[r release];
The following does not leak:
GADRequest *r = [[GADRequest alloc] init];
r.testing = YES;
// [bannerView_ loadRequest:r];
[r release];
I figure I'm changing the retain count on bannerView with the loadRequest but I don't know how to fix it. I tried a [bannerView_ release] immediately after the [r release]; line (i.e. releasing locally) but that didn't work. I didn't expect it to because bannerView_ is declared elsewhere. I tried [bannerView_ release]; in the dealloc method but that didn't work. I also tried [bannerView_ autorelease]; locally. The wise heads at Google put [bannerView_ release]; in the ViewDidUnload method.
It's possible that Instruments is just messing with my head. The leak appears after about 10 seconds but the app performs well and the amount of memory leaked doesn't seem to be spirally upwards as the app continues to run. Is there such a thing as a benign memory leak?
Thanks again for your help,
Dessie.
So I've got an NSFetchedResultsController that I activate on ViewDidLoad with the managedobjectcontext that has been passed on from the appdelegate on load.
I put a predicate on some field let's call it "sectionNumber" and say it needs to equal 1 in my predicate.
NSFetchResultsController works fine until I add a new object to the MOContext...
I use MyMO *newObj = [NSEntityDescription insertnewentity]...
start filling the different fields
[newobj setName:#"me"];
[newobj setAge:12];
etc...
Once I put [newobj setSectionNumber:1] - it finds it at that very instant and causes the app to crash with different weird errors that all lead to EXC_BAD_ACCESS.
All of this happens on the MAIN THREAD.
Any ideas why? How could one get around that?
UPDATE:
It only happens when I use my saveMOC method which is called at the end of an NSXMLParser specific thread I spawned off. The saveMOC is called on a successful parse with the [self performSelectorOnMainThread].... If i just added the extra managedobject via ViewDidLoad (just to check weather this is related somehow to to threading) the problem does NOT occur.
So it's obviously something with the new thread even tho the selector should have been run on the main thread.
UPDATE #2:
This is my spawned thread for the XML Parser:
-(void)getAndParseXML {
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
DLog(#"Online storage");
NSXMLParser *parser = [[NSXMLParser alloc] initWithContentsOfURL:theUrl];
XMLTranslator *translator = [[XMLTranslator alloc] init];
[parser setDelegate:translator];
if ([parser parse]) {
//success call MOC change routine on main thread
DLog(#"success parsing");
[self performSelectorOnMainThread:#selector(saveMOC:) withObject:translator waitUntilDone:NO];
} else {
DLog(#"error: %#",[parser parserError]);
}
[parser setDelegate:nil];
[parser release];
DLog(#"XML parsing completed");
[pool release];
}
Then this is my saveMOC:
-(void)saveMOC:(XMLTranslator*)translator {
NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
[formatter setDateFormat:#"yyyy-MM-dd HH:mm:ss"];
for (NSDictionary *dict in [translator retrievedData]) {
APost *newPost = [NSEntityDescription insertNewObjectForEntityForName:#"APost"
inManagedObjectContext:managedObjectContext];
//parse time into NSDate
[newPost setTime:[formatter dateFromString:[dict objectForKey:#"time"]]];
//author, category, description
[newPost setAuthor:[dict objectForKey:#"author"]];
[newPost setCategory:[dict objectForKey:#"category"]];
[newPost setContent:[dict objectForKey:#"description"]];
//create a post id so that the validation will be alright
[newPost setPostid:[NSNumber numberWithInteger:[[dict objectForKey:#"postid"] integerValue]]];
[newPost setSectionDesignator:sectionDesignator];
}
This saveMoc method continues and has a [managedobjectcontext save:&error] and more... but it's not relevan to our case as my method crashes I've discovered thru commenting one line after another at the point where I set the sectionDesignator since it equals to the current predicate in my NSFetchedResultsController.
The problem is most likely in the NSFetchedResultsController delegate methods or the lack thereof.
When you add a new object to any context and then save the context, that changes the persistent store which triggers the FRC on any thread to begin an update of the tableview. All the index paths change, especially if you set a value for an attribute used as a sectionNameKeyPath. If the table ask for a cell during the update, it will cause a crash because the table can ask for a cell at a index path rendered invalid by the insertion of the new managed object.
You need to make sure you implement the FRC's delegate methods and that you send the table a beginUpdate message to freeze it while the FRC changes all its index paths.
I am sorry to admit that the problem this whole time was releasing an array that held the sort descriptors in the fetch request that was used within the FRC.
Looking at alot of examples I released that array tho unlike the examples I created my array with [NSArray arrayWithObject:.............];
So there was an overrelease each time the fetch request was accessed more than once.
Feel free to close this. Thank you everybody for your help. I discovered this when peter wrote to look at the whole stack and not just one frame.
I have further analyzed the problem and have realized it occurs inside the loop.
I have further understood that it only happens when I have more than one object, meaning that one FRC takes over after an object insertion into MOC and tries to come back to the for loop, it tries to access an object or a reference that's not there. I haven't found what object causes it and how to retain it properly.
Any suggestions?
Consider the following:
for (int i=0; i<2; i++) {
NSLog(#"%i",i);
APost *thePost = [NSEntityDescription insertNewObjectForEntityForName:#"HWBPost" inManagedObjectContext:managedObjectContext];
[thePost setCategory:#"CAAA"];
[thePost setContent:#"SSSSSS"];
[thePost setSectionDesignator:sectionDesignator];
}
If I change the for loop to i<1 meaning it only runs once, the app does NOT crash. As soon as it is more than one object insertion the app crashes.