I have a general timer with a 1.5 second interval (the render cycle).
I have a class with an NSDate* member/property (nonatomic, retain).
I set this date by calling [callingClass setDate:expirationDate];
Now... a couple of render cycles this NSDate is valid. However, around the 3rd cycle the value of this variable gets corrupted, it seems.
When i set a break-point i notice that i can hover the mouse and see the data displayed properly (when its valid). But when its invalid i either see "out of scope", some weird strings (looks kinda like library file names or something), or in rare cases the debugger wont show me the value of any variable (i hate debugging in xcode).
So this is why i think this variable is getting corrupted somehow.
Should i be setting this synthesized property as (nonatomic, retain)? Or should it be declared as something else?
I think i found the problem.
I have a method called:
- (NSDate*) getNSDateFromString:(NSString*)stringDate;
When i called this i was doing NSDate *date = [self getNSDateFromString:expirationString];
This was causing the behavior i described above.
Then i changed it to the following which eliminated the crashings:
NSDate *date = [[self getNSDateFromString:expirationString] retain];
// do something with the date here...
[data release];
Related
as always relying on this community wich is always really helpful!
I really don't understand why my code isn't working, i am playing the game in ViewControllerA for example, there is "movements" and more stuff shown,wich are labels with int variables shown, this ones give me no problem because they change correctly,when the game is completed i want to show the score and more...
So i created another ViewController to do it, ViewControllerB for the example, the thing is that A and B Viewcontrollers belong to the SAME class, so i should be able to use the same variables, methods and everything ( actually i do that already and it's working fine)
I created IBOutlet for some labels, this ones belong to B. I am using presentViewcontroller method to show it up,the labels don't get anything changed, here is the code:
NSString *moviments = [NSString stringWithFormat:#"%d",TotalMovements];
NSString *score = [NSString stringWithFormat:#"%d",TotalPoints];
NSString *levelToShow = [NSString stringWithFormat:#"%d",PlayingLevel];
[movementsToShowOnCompletedScreen setText:moviments];
[scoreToShowOnCompletedScreen setText:score];
[levelToShowOnCompletedScreen setText:levelToShow];
UIStoryboard *winOFLevelStoryboard = [UIStoryboard storyboardWithName:#"Main" bundle:nil];
UIViewController *vc = [winOFLevelStoryboard instantiateViewControllerWithIdentifier:#"mainGame"];
[self presentViewController:vc animated:YES completion:^{
/*I have tried to add the same code from above setting the labels text
labels here, same result...
*/
}];
The labels don't get its text changed.
This is it, i hope with all of this you can find out what's going on here, the IBOutlets are fine, i even changed programmatically the frame of those labels before so that can't be the problem, outlets are fine.
If you need more code or anyhthing just let me know!
Thanks for your time !
Well, i found it...just in case anyone has the same problem. It solves it but not the way i wanted to so if anyone knows the good way please let me know.
Since those belong to the same class i have just copied/pasted this lines shown below to my viewdidload method, now labels are changing when they have to but i really think this is a really poor solution.
Thanks again!
Currently I didn't use ARC in my app, and I tried to create a NSAlert object as a local variable, at the end of function, I didn't release it.
I expected that the app crash with that, the function code is here.
#define GLOBAL_VARIABLE 0
NSString *msgText = [self.defaultValueTextFiled stringValue];
NSString *informativeText = #"Informative Text";
#if !GLOBAL_VARIABLE
NSAlert *alertView = nil;
#endif
if (alertView == nil)
{
alertView = [[NSAlert alloc] init];
[alertView setMessageText:msgText];
[alertView setInformativeText:informativeText];
NSTextField *accessory = [[NSTextField alloc] initWithFrame:NSMakeRect(0,0,200,22)];
[accessory setStringValue:#"accessory result"];
[alertView setAccessoryView:accessory];
}
NSView *accessory= nil;
NSInteger result = [alertView runModal];
if (result == NSAlertAlternateReturn)
{
accessory = [alertView accessoryView];
if (accessory != nil)
{
NSTextField *txtFiled = (NSTextField *)accessory;
NSLog(#"%ld", [accessory retainCount]);
NSString *str = [txtFiled stringValue];
NSLog(#"%ld", [accessory retainCount]);
[self.resultValueTextField setStringValue:str];
NSLog(#"%ld", [accessory retainCount]);
}
}
Questions:
(1) There is no [alertView release] in the end, why not crash? It has even no leaks.
(2) Refer to here , the accessory view shouldn't be release. However, I tried to release the view before [alertView runModal], then get its stringValue later, that could works. Why?
(3) The return value of function retainCount is interesting. When I created the alertView object, the retainedCount of alertView is 3. (Why?)
Before [alertView setAccessoryView:accessory], the accessory's retainedCount is 1, then it changed to 2 after executing it. That's normal and right. However, the log result for the above code, they're 20, 21, 22. How did they come from?
Thanks for your attention!
It does leak. Put a breakpoint on dealloc (or create a subclass of NSAlert and add a log statement to dealloc) to show this
The accessry view should be released. You alloc it and then it would be retained by the alertView
Here's a concise guide on when to use retainCount.
The rules for memory management are generally quite simple. Most problems come from overthinking them and trying to guess what other parts of the system are going to do, rather than just following the rules as written.
The first rule of Memory Management:
Use ARC.
If you cannot follow rule one (for instance, you are developing for OS X 10.5 as I do), then here are the rules:
You must balance each call you make to +alloc…, +new…, -…copy… or -retain with a call to -release or -autorelease.
That's really it. Everything else is really just commentary to help you follow that rule. So, you called [NSAlert alloc] and [NSTextField alloc], you need to call release on those objects.
Why doesn't it crash?
Because a leak is not going to crash unless it causes you to run out of memory.
Why doesn't it leak?
The most likely cause is that you're only running it once and then expecting Instruments to detect the leak. It may not show up if you only run it once. It depends on how NSAlert is internally implemented. Instruments finds leaks by walking all the pointers in the system and determining if any accessible pointers still reference a piece of allocated memory. There are many cases when a "leak is not a leak."
But this also suggests you're not running the static analyzer, because the analyzer should definitely have detected that leak. Run the static analyzer (Cmd-Shift-B) all the time and clean up what it finds.
the accessory view shouldn't be release.
That's not what the link you reference says. You shouldn't add an extra release. But in the referenced code, you'll notice that they release the view to balance their own +alloc.
… retainCount …
Never use -retainCount. Not even for debugging. Not even for anything else. There is no point at which retainCount is going to return you a piece of information that is going to be more enlightening than confusing. Why is it greater than you think it should be? Because other objects are retaining the alert view? Which objects? That's not your business. That's an internal implementation detail, subject to change. It could be pending autorelease calls, which show up temporarily as a "too high retainCount". It could be the run loop. It could be an internal controller. It could be anything. Calling retainCount tells you nothing useful.
Now that you understand manual memory management, switch to ARC and think about object graphs rather than retain counts. It is a much better way to deal with memory.
I have searched SO among other fora for the answer to this, but whatever I try, it does not seem to get rid of my memory leak. Does anybody have any suggestions?
I get a memory leak of 16 bytes per NSDate in my ViewController every time I present it.
-(void)initialise:(id)sender withDate:(NSDate *)date withMinimumDate:(NSDate *)minimum {
delegate = sender;
self.originalDate = [[NSDate alloc] init];
self.originalDate = date;
self.minimumDate = [[NSDate alloc] init];
self.minimumDate = minimum;
}
- (void)dealloc {
[self.originalDate release];
[self.minimumDate release];
[super dealloc];
}
I have tried releasing and/or making the NSDates nil before allocating them for the first time, and setting them to nil in the dealloc method.
They are declared as nonatomic and retained properties in the Header.
Have I missed something basic here or is there a more complex answer?
You are doing an alloc/init of a NSDate for originalDate, but then immediately abandoning it and setting it equal to the date parameter, possibly leaking the NSDate you created. You're doing this with minimumDate, too.
At a minimum, remove those two lines that do the alloc/init of the two respective NSDate objects that you subsequently abandon in favor for the parameters to the initialise method.
By the way, this problem (and the dealloc problem) would have been highlighted for you if you employed the static analyzer ("Analyze" on "Product" menu or press shift+command+B):
When writing manual reference counting code, the static analyzer is invaluable for identifying issues. You really should have a clean bill of health from the analyzer. You can click on the blue icons and it will often expand with the descriptions and arrows that I show in the above screen snapshot.
Note, this also highlighted the inappropriate use of self.originalDate (instead of _originalDate, or whatever the backing instance variable is) in your dealloc method. As I mentioned in my earlier comment, you should not use accessor methods in dealloc method.
These two lines are creating references to objects that are never released.
self.originalDate = [[NSDate alloc] init];
self.minimumDate = [[NSDate alloc] init];
Seeing as you instantly overwrite these properties with new values, you just need to delete these two lines (which are redundantly allocating NSDate objects that are never used) and your leak should go away.
You should also check whether delegate is properly memory managed too, as I see no release in dealloc for the delegate variable.
I am using the following code to deselect an NSTextView, as suggested here. Unfortunately, nothing at all happens. I have tried what I know to debug it, but everything seems to be working correctly, but it doesn't affect the NSTextView.
The code:
// Sets the scrolling bounds and behavior. This might be useful, but I don't know
[[textView textContainer] setContainerSize:NSMakeSize(FLT_MAX, FLT_MAX)];
[[textView textContainer] setWidthTracksTextView:FALSE];
// The code for deselecting, beginning by making sure it is actually selected (for testing only, as strange as it is)
[textView setSelectable:TRUE];
[textView setDelegate:self];
[_window makeFirstResponder:textView];
NSText *fieldEditor = [_window fieldEditor:TRUE forObject:textView];
[fieldEditor setSelectedRange:NSMakeRange([[fieldEditor string] length],0)];
[fieldEditor setNeedsDisplay:YES];
Any ideas about why this doesn't work? I am sure my outlets are set properly because I can manipulate other things, such as it's string value.
I'm not sure NSTextViews use the field editor, have you tried calling the method on the text view directly?
[textView setSelectedRange:NSMakeRange(textView.string.length, 0)];
The range location can be adjusted to move the cursor to the start or end, for example. You may also want to check to make sure something is actually selected before calling this method.
EDIT:
From your comment it sounds like you just want it to resign first responder. You can do that manually by calling [textView.window makeFirstResponder:nil];
This almost worked for me;
[textView.window makeFirstResponder:nil];
However, I had trouble setting the first responder to nil. If I set it to any other view it seems to do as you want.
[textView.window makeFirstResponder:[textView superview]];
Tested in 10.7 Lion.
I've using this approach and it works perfectly:
[textView setSelectedRange:NSMakeRange(0, 0)];
As suggested earlier setSelectedRange: will do the trick BUT!
If your goal is to completely remove the selection and the cursor too, f.e. if you subclass an NSTextView to support similar behavior like NSTextEdit has in case of firstResponder status change you should write:
- (BOOL)resignFirstResponder
{
// Invalid range location will remove cursor too
[self setSelectedRange:NSMakeRange(NSUIntegerMax, 0)];
return YES;
}
//------------------------------------------------------------------------------
- (BOOL)becomeFirstResponder
{
[self setSelectedRange:NSMakeRange(0, self.string.length)];
return YES;
}
//------------------------------------------------------------------------------
[textView setDelegate:self];
I have a feeling that one of your delegate methods is preventing things from happening. See the documentation under "Managing the selection".
As a temporary solution, just until somebody comes up with a better idea, setHidden: can be used. I am sure this is not as efficient as is recommended, but it deselects the NSTextView.
Simply toggle it twice, like so:
[textView setHidden:TRUE];
[textView setHidden:FALSE];
I have an ImageView which shows a lock, informing if an opened file is locked or not. I have 2 images for locked and unlocked cases. I want synchronize the displayed image with boolean value of my object representing an opened file.
To do this I want my ViewController to change the image in my ImageView depending on lock state of object. So both object and ViewController have a property "isLocked".
How can I synchronize them? It is easy in IB but I don't know how to do it programmatically. I tried in initialize method of my ViewController to use:
[ViewController bind:#"value" toObject:[ArrayController selection] withKeyPath:#"isLocked" options:nil];
But it doesn't work. In documentation it is said that I have to expose my binding before using it.
I try to put the following code in initializer method of my object:
[self exposeBinding:#"isLocked"];
But Xcode doesn't recognize this method.
Does somebody have experience with this kind of bindings establishing?
As #nick says, you want Key-Value-Observing.
[arrayController addObserver:self
forKeyPath:#"selection.isLocked"
options:NSKeyValueObservingOptionNew
context:#"this_context"]
Then when isLocked changes the -observeValueForKeyPath:ofObject:change:context: method that you have added to your viewController will be called (as long as you only manipulate isLocked in a KVC compliant way).
The options parameter lets you optionally tweak exactly what conditions will trigger the notification and what data is sent along with the notification. The context parameter is there to help you distinguish between notifications that you registered to receive and notifications your superclass registered to receive. It is optional.
Bindings seem like they might be useful to keep two values in sync. However, this is not what they do at all.
Yes, lots of things seem to give the impression that this is what they do, and there isn't much saying that this isn't what they do, also lots of people believe that this is what they do - but no, you cannot use them for this.
Only a handful of classes support bindings (they are listed here) and then, and this is the important bit, those classes only support binding their named bindings, and these bindings are not instance variables. eg NSTextField has a 'fontFamilyName' binding yet NSTextField does not have a 'fontFamilyName' property or instance variable, even a derived one. NSTextField does have a 'isBordered' property but not a binding - so you cannot bind 'isBordered'.
It does not mean anything to 'bind' an arbitrary property of an arbitrary Class.
Yes, you can bind two arbitrary values, the following code works just fine:
#import <Cocoa/Cocoa.h>
#interface SomeObject : NSObject
#property (retain,nonatomic) id someValue;
#end
#implementation SomeObject
#end
int main()
{
SomeObject *source=[SomeObject new];
SomeObject *target=[SomeObject new];
[target bind:#"someValue" toObject:source withKeyPath:#"someValue" options:0];
[source bind:#"someValue" toObject:target withKeyPath:#"someValue" options:0];
[source setSomeValue:#(42)];
NSLog(#"target: %#",[target someValue]);
[target setSomeValue:#(22)];
NSLog(#"source: %#",[source someValue]);
return 0;
}
As far as I can tell, the problem is the bit [ArrayController selection]. The first problem is that ArrayController is (or should be) a class, and getting the class's selection is probably pointless. The other problem is that even if this were an instance, you would be binding to the selection at the time of the call, which is almost certainly not what you want. You want to track the current selection as it changes.
So what you want is probably something like the following:
[myViewController bind:#"value" toObject:myArrayController withKeyPath:#"selection.isLocked" options:nil];