I am new to objective-c. My object reportingTime is nil in init method. What I am doing wrong ? How can I initialize reportingTime and set firstweekday ?
I have the following interface and implementation
My interface file Calculation.h
#interface Calculate : NSObject {
NSCalendar *reportingTime;
....
....
}
#property NSCalendar *reportingTime;
#end
And my implementation file Calculate.m
#import "Calculate.h"
#implementation Calculate
#synthesize reportingTime;
- (id)init
{
if(self = [super init]) {
reportingTime = [[NSCalendar alloc] init];
[reportingTime setFirstWeekday:1];
// reportingTime is nil ??????
}
return self;
}
Use
- (id)initWithCalendarIdentifier:(NSString *)string
instead of standart init method.
See more: https://developer.apple.com/library/mac/#documentation/Cocoa/Reference/Foundation/Classes/NSCalendar_Class/Reference/NSCalendar.html
Instead of
reportingTime = [[NSCalendar alloc] init];
use:
reportingTime = [[NSCalendar currentCalendar] retain];
The retain because this is a direct assignment to the #property ivar and [NSCalendar currentCalendar] is a convenience method that returns an autoreleased var. If you are using ARC the retain is not necessary.
Related
Stubbing NSDate to return a mock date can easily be done using category except for -[NSDate init]. -[NSDate init] is not called unlike other methods. class_addMethod does not help. method_exchangeImplementations, method_setImplementation on -[NSDate init] actually change -[NSObject init] but no effect on -[NSDate init].
[NSDate setMockDate:[NSDate dateWithTimeIntervalSinceReferenceDate:0]];
NSDate *date1 = [NSDate date];
NSLog(#"%#", date1);
NSLog(#"%.0f", [date1 timeIntervalSinceNow]);
// _replacement_Method is not called!
NSDate *date2 = [[NSDate alloc] init];
NSLog(#"%#", date2);
NSLog(#"%.0f", [date2 timeIntervalSinceNow]);
// _replacement_Method is called
NSObject *object = [[NSObject alloc] init];
NSLog(#"%#", object);
// A class with empty implementation to test inherited init from NSObject
// _replacement_Method is called by -[MyObject init]
MyObject *myobject = [[MyObject alloc] init];
NSLog(#"%#", myobject);
The output is
2001-01-01 00:00:00 +0000
-0
2014-11-26 14:43:26 +0000
438705806
<NSObject: 0x7fbc50e19d90>
<MyObject: 0x7fbc50e4ad30>
NSDate+Mock.m
#import "NSDate+Mock.h"
#import <mach/clock.h>
#import <mach/mach.h>
#import <objc/runtime.h>
static NSTimeInterval sTimeOffset;
static IMP __original_Method_Imp;
id _replacement_Method(id self, SEL _cmd)
{
return ((id(*)(id,SEL))__original_Method_Imp)(self, _cmd);
}
#implementation NSDate (Mock)
+ (NSObject *)lock
{
static dispatch_once_t onceToken;
static NSObject *lock;
dispatch_once(&onceToken, ^{
lock = [[NSObject alloc] init];
});
return lock;
}
+ (void)setMockDate:(NSDate *)date
{
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
Method m1 = class_getInstanceMethod([NSDate class], #selector(init));
Method m2 = class_getInstanceMethod([NSDate class], #selector(initMock));
// method_exchangeImplementations(m1, m2);
// class_addMethod([NSDate class], #selector(init), (IMP)_replacement_Method, "##:");
__original_Method_Imp = method_setImplementation(m1, (IMP)_replacement_Method);
});
#synchronized([self lock]) {
sTimeOffset = [date timeIntervalSinceReferenceDate] - [self trueTimeIntervalSinceReferenceDate];
}
}
+ (NSTimeInterval)mockTimeOffset
{
#synchronized([self lock]) {
return sTimeOffset;
}
}
+ (NSTimeInterval)trueTimeIntervalSinceReferenceDate
{
clock_serv_t cclock;
mach_timespec_t mts;
host_get_clock_service(mach_host_self(), CALENDAR_CLOCK, &cclock);
clock_get_time(cclock, &mts);
mach_port_deallocate(mach_task_self(), cclock);
NSTimeInterval now = mts.tv_sec + mts.tv_nsec * 1e-9 - NSTimeIntervalSince1970;
return now;
}
+ (NSTimeInterval)timeIntervalSinceReferenceDate
{
return [self trueTimeIntervalSinceReferenceDate] + [self mockTimeOffset];
}
+ (instancetype)date
{
return [[NSDate alloc] initWithTimeIntervalSinceNow:0];
}
+ (instancetype)dateWithTimeIntervalSinceNow:(NSTimeInterval)secs
{
return [[NSDate alloc] initWithTimeIntervalSinceNow:secs];
}
//- (instancetype)init
//{
// self = [super init];
// return self;
//}
//- (instancetype)initMock
//{
// self = nil;
// NSDate *date = [[NSDate alloc] initWithTimeIntervalSinceNow:0];
// return date;
//}
- (instancetype)initWithTimeIntervalSinceNow:(NSTimeInterval)secs
{
return [self initWithTimeIntervalSinceReferenceDate:[NSDate timeIntervalSinceReferenceDate] + secs];
}
- (NSTimeInterval)timeIntervalSinceNow
{
NSTimeInterval t = [self timeIntervalSinceReferenceDate];
return t - [NSDate timeIntervalSinceReferenceDate];
}
#end
NSDate has to important characteristics:
It is a class cluster
It is immutable
In such a case, +alloc returns only a placeholder and you send -init… to that placeholder (of class __NSPlaceholderDate). Replacing -init (NSDate) has no effect, if -init (__NSPlaceholderDate or NSWhatever is implemented.)
This is, because +alloc cannot decide which (private) subclass to choose, because it has no parameters. (They are passed at the -init….)
You can
simply replace -init of __NSPlaceholderDate
replace -init of what +alloc returns.
replace +alloc to return your private placeholder and overwrite -init in it.
If you need mock dates e.g. in your tests, consider instantiating the NSDate objects with the Factory pattern and replacing the factory for production or tests. This way only your own classes end up with the mock dates and you don't have to worry about accidentally replacing methods that may be used by Apple's frameworks.
i have a property
//.h
#property (nonatomic, retain) SomeCLass * someSynthInstance;
//.m
#synthesize someSynthInstance = _someSynthInstance;
- (void) foo
{
self.someSynthInstance = [[SomeCLass alloc] init];
//[self.someSynthInstance release]; <- SHOULD I RELEASE HERE???
}
- (void) dealloc
{
self.someSynthInstance = nil;
}
my theory goes, that [alloc, init] creates a count of 1, and the setter, inc that count, so it becomes 2, therefore i should release it, right after
but aim getting exc_bad_access in the application after i changed everything like this, so aim not sure if its ok
you want to be releasing the instance variable rather than the property. so you can do either:
self.someSynthInstance = [[[SomeCLass alloc] init] autorelease]; // puts it in the autoreleasepool so it'll get released automatically at some point in the near future
or
_someSynthInstance = [[SomeCLass alloc] init]; // skip the property
or
self.someSynthInstance = [[SomeCLass alloc] init];
[_someSynthInstance release]; // call release on the instance variable
The standard practice is:
SomeClass *tmpObj = [[SomeClass alloc] init];
self.someSynthInstance = tmpObj;
[tmpObj release];
you should release the class variable instead.. like [_someSynthInstance release]; that should do the trick.
yes you should release after init
SomeCLass *temp = [[SomeCLass alloc] init];
self.someSynthInstance = temp;
[temp release]
Please help;
Header File
#import <Foundation/Foundation.h>
#interface MyClass : NSObject {
NSMutableString * myString;
}
#property (nonatomic, retain) NSMutableString * myString;
-(id) init;
-(void) dealloc;
#end
Implementation File
#import "MyClass.h"
#implementation MyClass
#synthesize myString;
-(id) init {
if ((self = [super init])) {
self.myString = [[NSMutableString alloc] init];
}
return self;
}
-(void) dealloc {
[super dealloc];
[self.myString release];
}
#end
Usage
MyClass * m = [[MyClass alloc] init];
[m release];
//-- Xcode 4 profiler reports a memory leak here.
However, when the code in implementation file of the class is changed to not use the [self.myString .....] notation, then no memory leak is reported.
So,
-(id) init {
if ((self = [super init])) {
myString = [[NSMutableString alloc] init];
}
return self;
}
}
and
-(void) dealloc {
[super dealloc];
[myString release];
}
works fine. No memory leaks reported.
Any ideas - is it profiler or is it me (be nice)?
Your memory leak is not caused by using your setter. Your memory leak is caused by you not managing your memory correctly!
If you declare the following property
#property (nonatomic, retain) id value;
That means that the compiler generates methods that look something like this (highly simplified):
- (id)value {
return value;
}
- (void)setValue:(id)aValue {
[value autorelease];
value = [aValue retain];
}
When you use dot-notation, self.value = obj is desugared into [self setValue:obj]. Thence, you are actually causing obj to be retained within the setter. If you initially create an owning reference to obj (by using an +alloc without a corresponding -release or -autorelease), you'll have over-retained obj, and it will never be deallocated. Hence, you need to do something like this:
id obj = [[[NSObject alloc] init] autorelease];
self.value = obj;
or
id obj = [[NSObject alloc] init];
self.value = [obj autorelease];
or
id obj = [[NSObject alloc] init];
self.value = obj;
[obj release];
Whatever you do, you need to make sure that when you assert ownership of an object (by retaining it), you also release it.
Setter methods in Objective-C equate to a reatain of the new object and release of the old object. In your case the compiler will generate a setter method for your myString property that looks something like...
- (void)setMyString:(NSMutableString*)aString {
[myString autorelease];
myString = [aString retain];
}
When you invoke self.myString = in your init method this translates to a call to the setter. The setter in turn retains the object you pass to it. Because you've directly alloc'd the NSString it begins life with a retain count of one, you then call the setter and the retain count becomes two.
There's two approaches to fixing the problem, the first would be to add a call to [myString autorelease] after you alloc it. Or secondly switch your init method to directly assign the ivar...
// in your init method...
myString = [[NSMutableString alloc] init];
It's a good idea to avoid setter usage in init methods, not because of retain counts but because the object as a whole is not yet fully initialized.
#property (nonatomic, RETAIN)
you are retaining my friend. You have to release the object twice then because the retain count is 2
here is what you should do in the INIT method:
NSString *str = [[NSString alloc] initWithString:#"Hello World!"];
self.myString = str;
[str release]; // dont leak
Also I do not recommend using self.someProperty in the class itself. Doing so requires 1 extra objc_msgSend() to be done to access your variable and will slow down your application.
Assume I have a interface like:
#interface it:NSObject
{
NSString* string;
}
#end
#implement it
-(id)init
{
if(self = [super init]){
self.string = [[NSString alloc]init];
}
}
-(void)dealloc
{
[self.string release];
[super release];
}
#end
If I use this class in another file and I call this:
it ait = [[it allow] init];
NSString* anotherString = [[NSString alloc] init];
ait.string = anotherString;
[anotherString release];
Will this cause the string alloced in init method of it a memory leak?
Since the string is not referenced and not autoreleased.
If I don't alloc a string in the init method, what will happen when I call ait.string right before assign anotherString to it?
I think you need
#property (nonatomic, retain) NSString *string;
in your interface and
#synthesize string;
in your implementation for self.string to work.
Then, when you do
self.string = [[NSString alloc] init];
in your init method the string will actually have a retain count of 2 because [[NSString alloc] init]will return a string with a retain count of 1, and using self.string = will retain the object again because the property is declared as 'retain'. This will result in a memory leak, but you can fix by having:
-(id)init
{
if(self = [super init]){
self.string = #"initString";
}
}
or similar.
Then, onto the actual question, if you do as above the string allocated in init wont leak when you reassign with self.string = because properties marked as 'retain' release their current object before retaining the new one.
If you don't assign a string to self.string in the init method it doesn't matter because self.string will just return nil, which you can then deal with in your program.
Will this cause the string alloced in
init method of it a memory leak? Since
the string is not referenced and not
autoreleased.
Yes, exactly. You seem to have got it.
If I don't alloc a string in the init
method, what will happen when I call
ait.string right before assign
anotherString to it?
Do you mean in the following case you are unsure what unknownObject would refer to?:-
It *ait = [[It allow] init];
NSString *unknownObject = ait.string;
This is nonsense. Did you forget to add the accessor methods?
Objective-c doesn't use 'dot syntax' to access instance variables, like, say, Java. If you have an instance of your class 'it' you can only access the 'string' variable from outside that instance by calling the accessor 'getter' method. This is not optional self.string is just a shortcut for the method call [self string] and this method doesn't exist in the code you showed.
Assuming the accessor method are defined elsewhere, the instance variable you called string (this is the worlds worst variable name) is equal to nil. In Objective-c you have to treat nil objects very carefully as the behaviour is different from how many other languages treat the similar null.
In Objective-c this is fine:
NSString *nilString = nil;
[nilString writeToFile:#"/this_file_cannot_exist.data"];
Many other languages would crash here or throw an exception; This can be dangerous, as an operation may fail but your app will continue running. It can also be great tho, because in other languages you will see lots of this..
someObject = controller.currentValue()
if( someObject!=null )
someObject.writeToFile("myFile.data")
In Objective-c the 'if(..)' line isn't needed at all.
You must be careful not to call the accessor method inside your init and dealloc methods, as this can break subclasses. Instead of
- (void)dealloc {
[self.string release]; // This is [[self string] release]
...
you should just use
- (void)dealloc {
[string release];
...
As well as being dangerous the call to [self string] is unnecessary. The same is true in your init methods
if(self=[super init]){
self.string = [[NSString alloc]init]; // shortcut for [self setString:[[NSString alloc] init]]
...
just use
if(self=[super init]){
string = [[NSString alloc] init];
...
You're missing the #property in order to use self.string.
Add this to your .h file
#property (readwrite, copy) NSString *string;
Using Copy instead of Retain will prevent the string from memory-leak even if you release anotherString.
#interface it:NSObject
{
NSString* string;
}
//you should declare a property in order to call it with 'self' prefix
#property (nonatomic, retain) NSString* string;
#end
#implementation it
//you should synthesize your property
#synthesize string;
-(id)init
{
if(self = [super init]){
//you don't to initialize NSString right here (memory leak will have place)
//self.string = [[NSString alloc]init];
//you can store a default value like this (can be omitted):
self.string = #"Default value";
}
return self;
}
-(void)dealloc
{
[self.string release];
[super release];
}
#end
And everything regarding memory management in this class will be fine.
I'm new to Objective-c. For learning purposes I'm trying to build something like a phonebook. So I'll have a class called Person that will have some properties (name, phone, etc).
Right now I'm not preoccupied about persistence. But, I need something to "hold" Person objects. So I thought about create a class called People, but I don't know how to design it, specially the NSMutableArray that will hold the objects.
What I did was:
PERSON.H
#interface Person : NSObject {
NSString *name;
}
#property(readwrite, copy) NSString *name;
#end
PERSON.M
#implementation Person
#synthesize name;
#end
PEOPLE.H
#interface People : NSObject {
NSMutableArray *peopleArray;
}
#property(readwrite, retain) NSMutableArray *peopleArray;
- (void)addPerson:(Person *)objPerson;
#end
PEOPLE.M
#implementation People
#synthesize peopleArray;
- (id)init {
if (![super init]) {
return nil;
}
peopleArray = [[NSMutableArray alloc] retain];
return self;
}
- (void)addPerson:(Person *)objPerson {
[peopleArray addObject:objPerson];
}
PHONEBOOK.M
...
Person *pOne = [[Person alloc] init];
pOne.name =#"JaneDoe";
People *people = [[People alloc] init];
[people addPerson:pOne];
When I try to use this code, I receive an error:_method sent to an uninitialized mutable array object.
So, since I'm a newbie, probably the way that I did isn't the best/correct one. So, how do I do this?
Two things wrong with your initialiser for people. It should look more like this:
- (id)init {
self = [super init]; // always assign the result of [super init] to self.
if (!self) {
return nil;
}
peopleArray = [[NSMutableArray alloc] init]; // use init not retain.
return self;
}
Because you're not calling init on the NSMutableArray when you create your peopleArray. Try calling:
peopleArray = [[NSMutableArray alloc] init];
instead. You need not retain it unless you say for instance, did this:
peopleArray = [[NSMutableArray array] retain];
For reasons why, see the rules for memory management. These rules are very important for any iPhone or Mac developer to understand, and quite frankly, are simple enough that there's no excuse. :)
In People.m you probably meant to write
peopleArray = [[NSMutableArray alloc] init];
instead of
peopleArray = [[NSMutableArray alloc] retain];