NSDate throwing BAD_EXCESS for what? - ios

I have below.
#interface MyViewController () {
NSDate *myCurrentDate;
}
#implementation MyViewController
-(void)viewDidLoad {
[super viewDidLoad];
myCurrentDate = [NSDate date];
}
- (IBAction) prevAction:(id)sender {
NSLog(#"myCurrentDate===%#", myCurrentDate); // here it says
myCurrentDate = [myCurrentDate dateByAddingTimeInterval:60*60*24*-1];
[self formatDateAndPostOnButton];
}
When I try to print current date as below, it crash saying BAD_EXCESS
NSLog(#"myCurrentDate===%#", myCurrentDate);
Below is the screenshot for the same.
I'm not using ARC in my project.
Any idea what is going wrong?

Since you are not using ARC, easiest way to retain objects is to use generated setters/getters.
Instead of:
#interface MyViewController () {
NSDate *myCurrentDate;
}
make
#interface MyViewController ()
#property(nonatomic, retain) NSDate* myCurrentDate;
#end
So it will keep NSDate retained. Right now your NSDate gets deallocated when the auto-release pool is drained.
You will need to use the getters/setters provided, however:
self.myCurrentDate = [self.myCurrentDate dateByAddingTimeInterval:60*60*24*-1];
Anyways I would recommend start using ARC to make your life simpler and avoid strange memory crashes.

Related

NSUndoManager removeAllActionsWithTarget crash

I have some abbreviated iOS Objective-C sample code (simplified from a larger project) that causes a crash in NSUndoManager that I can't explain.
Namely, when an object that is only held onto by the NSUndoManager deallocs (because it's beyond the levels of undo), and, according to the docs calls removeAllActionsWithTarget:self, I get an EXC_BAD_ACCESS.
// SimpleViewController.m
#interface ViewController ()
#property (nonatomic, strong) NSUndoManager *undoManager;
#end
#implementation ViewController
#synthesize undoManager;
// called from a simple button
- (IBAction)doItTapped:(id)sender
{
CoolObject *object = [CoolObject new];
object.undoManager = self.undoManager;
// according to docs, object will be retained by NSUndoManager here
// but target will not (which should be okay)
[self.undoManager registerUndoWithTarget:self selector:#selector(notCool:) object:object];
}
- (void)viewDidLoad
{
[super viewDidLoad];
self.undoManager = [NSUndoManager new];
self.undoManager.levelsOfUndo = 3;
}
and
// CoolObject.m
#implementation CoolObject
- (void)dealloc
{
[self.undoManager removeAllActionsWithTarget:self];
}
#end
After the 4th tap of the button (levelsOfUndo + 1), it crashes.
If I swap NSUndoManager with GCUndoManager, no crash.
Tested in iOS 10.2 sim and devices.
Thanks for any ideas!
Their are chances that you might be getting this error because self.undoManager is not retained at that point where you are using it. When the object is already deallocated and you try to access it, you will get bad access exception.
Try to change your code from this:
CoolObject *object = [CoolObject new];
to this:
#interface ViewController (){
CoolObject *object;
}
#property (nonatomic, strong) NSUndoManager *undoManager;
#end
#implementation ViewController
- (IBAction)doItTapped:(id)sender
{
object = [CoolObject new];
object.undoManager = self.undoManager;
// according to docs, object will be retained by NSUndoManager here
// but target will not (which should be okay)
[self.undoManager registerUndoWithTarget:self selector:#selector(notCool:) object:object];
}
#end
Hope this will help.
Just like me, you seem to have misinterpreted the admittedly inaccurately written documentation. The docs talk about "target", "object" and "target object" as if they were different things when they really mean exactly one and the same: the (id)target parameter of -removeAllActionsWithTarget:
In other words, in my opinion you should not need to call -removeAllActionsWithTarget: inside of CoolObject at all because CoolObject has been specified as the object of -registerUndoWithTarget:selector:object: whereas the target is your ViewController.
You may have to call -removeAllActionsWithTarget: in your NSViewController's -dealloc but even that is unnecessary in your example because your NSViewController owns the NSUndoManager and thus ViewController won't go away before undoManager does.

Getting date from core data swift

Am trying to display the timestamp a new post is made on a label but in don't seem to get around with it please help
Have tried using NSDate() but am getting an abort() error from the Appdelegate
You would need to add a property to the entity called creationDate and sets its value on insert.
#interface YourEntity : NSManagedObject
#property (nonatomic, copy) NSDate *creationDate;
#end
#implementation YourEntity
#dynamic creationDate;
- (void)awakeFromInsert
{
[super awakeFromInsert];
self.creationDate = [NSDate date];
}
#end
Then, just access the property when you need it.

Unknown receiver datePicker

I'm following a tutorial from Lynda regarding creating a UIDatePicker, and here's what my code looks like:
ViewController.h
#import <UIKit/UIKit.h>
#interface ViewController : UIViewController
#property (weak, nonatomic) IBOutlet UIDatePicker *datePicker;
...
#end
ViewController.m
#import "ViewController.h"
...
#implementation ViewController
...
- (IBAction)displayDate:(id)sender {
NSDate *chosen = [datePicker date];
...
}
#end
but for some reason XCode is giving me an error:
"unknown receiver 'datePicker'
Just a note, the datePicker is linked. Is there something that I'm missing?
Forget to #syntesize
Your UIPickerView to your .m file
and also your can access by UIPickerView by name _datePicker
In this case you have datePicker property which is accessible by self.datePicker, or instance variable (generated for you by compiler) _datePicker. You really want the former.
When using properties, you must call self first:
NSDate *chosen = [self.datePicker date];
Or
NSDate *chosen = [[self datePicker] date];

Lazy Load Property in iOS 5+ with ARC

Problem
I am migrating some legacy code (pre iOS 5) where I lazy load some readonly properties. I want to update this code to iOS 5+ with ARC. But I just learning about ARC.
.h
#property (nonatomic, retain, readonly) NSDateFormatter *timeFormatter;
.m
- (NSDateFormatter *)timeFormatter {
if (timeFormatter == nil) {
timeFormatter = [[NSDateFormatter alloc] init];
[timeFormatter setDateFormat:#"h:mm a"];
}
return timeFormatter;
}
What I tried
I have tried to simply update my code, but receive an: Assignment to readonly property.
.h
#property (nonatomic, strong, readonly) NSDateFormatter *timeFormatter;
.m
- (NSDateFormatter *)timeFormatter {
if (self.timeFormatter == nil) {
self.timeFormatter = [[NSDateFormatter alloc] init];
[self.timeFormatter setDateFormat:#"h:mm a"];
}
return self.timeFormatter;
}
I also reviewed:
ios ARC strong and alloc
Thread safe lazy initialization on iOS
http://www.cocoanetics.com/2012/02/threadsafe-lazy-property-initialization/
Question
What is the correct way to lazy-load a readonly property in iOS 5+ with ARC? Would appreciate code samples for both .h and .m.
For a custom (lazy) getter method you have to access the instance variable directly (whether you use ARC or not). So you should synthesize the property as
#synthesize timeFormatter = _timeFormatter;
Then your getter method is
- (NSDateFormatter *)timeFormatter {
if (_timeFormatter == nil) {
_timeFormatter = [[NSDateFormatter alloc] init];
[_timeFormatter setDateFormat:#"h:mm a"];
}
return _timeFormatter;
}
You only have to add some synchronization mechanism if the property is accessed from multiple threads concurrently, that is also independent of ARC or not.
(Remark: Newer Xcode versions can create a #synthesize statement automatically and use the underscore prefix for instance variables. In this case however, since the property is read-only and you provide a getter method, Xcode does not synthesize the property automatically.)
ADDED: Here is a complete code example for your convenience:
MyClass.h:
#import <Foundation/Foundation.h>
#interface MyClass : NSObject
#property (nonatomic, strong, readonly) NSDateFormatter *timeFormatter;
#end
MyClass.m:
#import "MyClass.h"
#implementation MyClass
#synthesize timeFormatter = _timeFormatter;
- (NSDateFormatter *)timeFormatter {
if (_timeFormatter == nil) {
_timeFormatter = [[NSDateFormatter alloc] init];
[_timeFormatter setDateFormat:#"h:mm a"];
}
return _timeFormatter;
}
#end
MORE INFORMATION: In fact, your pre-ARC timeFormatter getter method works without changes also with ARC, if the property is synthesized as
#synthesize timeFormatter; // or: #synthesize timeFormatter = timeFormatter;
The only "mistake" you made was to replace timeFormatter by self.timeFormatter inside the getter method. This creates two problems:
Reading self.timeFormatter inside the getter method leads to infinite recursion.
Setting self.timeFormatter is not allowed because of the read-only attribute.
So if you just leave the timeFormatter getter method as it was (using the timeFormatter instance variable inside the method) then it works also with ARC.
I would still recommend to prefix instance variables for properties with an underscore as in my code example, because Xcode does it the same way for automatically synthesized properties.
(I hope that this helps and does not increase the confusion!)
Readonly properties are just that: read only. There should be no setters involved. The nice part is, if you redeclare the variable in a class extension (usually with a pair of empty parenthesis), as readwrite (or even just remove the readonly entirely), then you can assign to it within the .m, but classes that import it will see it as readonly.
#interface MyClass ()
#property (nonatomic, strong) NSDateFormatter *timeFormatter;
#end
This redeclaration allows a cleaner way to access and mutate the property internally without resorting to fragile iVar synthesis (which is becoming an antiquity now that the compiler does it for you). You can, or course, still use the iVar as shown in the other answer, but iVar access outside of -init or synthesized getters is unnecessary.*
*As Martin correctly pointed out, even if your assignment had succeeded, you still would have caused an infinite recursion, so iVar access is necessary, unless you explicitly declare a getter, then you may use property access.

Instruments Leaks shows non-existent method call

Either I don't understand the Instruments Leaks tool at all, or I am going mad. I have run the tool on my iphone app, and it shows a couple of leaks. If I understand it correctly, for one of the leaks, it says that it is an NSDate object allocated by my method "writeHeading". The method that allocates the object is: "dateWithTimeIntervalSinceReferenceDate:". However, my writeHeading method does not use that method. In fact, that method is not used anywhere in my whole application.
Does anybody have an idea what could be going on here?
Here is the code of writeHeading:
- (void) writeHeading:(CLHeading *)heading
{
if (self.inFlight) {
[log writeHeading:heading];
} else {
IGC_Event *event = [[IGC_Event alloc] init];
event.code = 'K';
event.timestamp = heading.timestamp;
event.heading = heading;
[self addEvent:event];
[event release];
}
}
Here is a screenshot of Instruments:
And here is the definition of IGC_Event (as asked by multiple responders):
#interface IGC_Event : NSObject {
int code;
CLLocation *location;
CLHeading *heading;
NSString *other;
NSDate *timestamp;
}
#property int code;
#property (nonatomic, retain) CLLocation *location;
#property (nonatomic, retain) CLHeading *heading;
#property (nonatomic, retain) NSString *other;
#property (nonatomic, retain) NSDate *timestamp;
#end
#implementation IGC_Event
#synthesize code;
#synthesize location;
#synthesize heading;
#synthesize other;
#synthesize timestamp;
#end
Assuming no ARC, you need to make sure IGC_Event objects release their timestamp and other references that may have been retained or copied.
So in IGC_Event you need a dealloc something like this:
- (void) dealloc {
[timestamp release];
[location release];
[heading release];
[other release];
[super dealloc];
}
Leaks is just telling you where that timestamp object was created, not where you should have released it.
That may not be the only place you are leaking of course, but that's 4 potential leaks right there.
When the compiler runs your code, there are the methods directly called by you (which in your screenshot have a little person next to them) and then the methods that are invoked in the core frameworks as a result. The method in question results from this piece of code:
event.timestamp = heading.timestamp;
You could manage this process yourself if you wanted to:
NSDate *eventTimestamp = heading.timestamp;
event.timestamp = eventTimestamp;
Incidentally, storing that timestamp is entirely redundant and uses unnecessary memory, since you also store the heading with all its properties in event.heading so at any time you can access that timestamp with event.heading.timestamp. However, you may have other reasons for storing it separately.
Do you have the implementation of the IGC_Event class? Is it possible that the setter for its timestamp property is calling dateWithTimeIntevalSinceReferenceDate:? (Not an unreasonable thing to do, so far as I can tell. That would ensure that its timestamp is of class NSDate itself, and not a subclass. It would also ensure that it's independent of the timestamp that was passed in.)
(Disclaimer: I'm really not much of an Objective-C-er. If this seems like a stupid question, then it probably is!)

Resources