What is the reference count of an object in the following program? - ios

1) Disabled ARC.
2) I have the following code:
- (IBAction)btnsecondClicked:(id)sender {
NSString *myname;
myname = retrieveName();
}
NSString * retrieveName()
{
NSString *tmpStr = [[NSString alloc] initWithString "StackOverFlow"];
return tmpStr;
}
I tried with Analyser, and it says
"Object Leaked: allocated object is not referenced later in this execution path and has
a retain count of +1"
point at line next to line where retrieName was invoked.
My question:
What is the retain count of the the object ? Should not it be to 2 ?
because:
the first reference count is in retrieveName()
2.the second count is in btnsecondClicked(), where myname variable holds ?
ie: myname = retrievedName () -> Does not it increase the reference count ?

In this step, you've created string NSString *tmpStr = [[NSString alloc] initWithString "StackOverFlow"];. So you've +1 reference count, because always alloc: returns object with +1 count. Then where will you release this? That's why It shows as leak.

Think in terms of ownership — focus on the semantics of what you want to say, not the way the implementation has been written. This is object-oriented programming.
Whomever calls alloc gets an owning reference. Anybody that calls retain establishes ownership. So every call to either alloc or retain must be matched by a release — either an immediate release or an autorelease if you want it taken care of autonomously.
The norm for results on the stack is to autorelease. That's even enshrined in the rule that factory methods (e.g. [NSString +string] return such a non-owning reference.

No, because passing an object around does not add nothing to the retain count.
However, if you did
- (IBAction)btnsecondClicked:(id)sender {
NSString *myname;
myname = [retrieveName() retain];
}
Then the retain count would increase to 2, because you are explicitly declaring ownership on that particular object.

- (IBAction)btnsecondClicked:(id)sender {
NSString *myname; // nil object, no retain count
myname = retrieveName(); // we received the object with retain count 1 (not 2 because you are not sending `retain` to the received object)
} // you exited the function without having global reference on the object, mynames is lost because it was created inside the function, i.e. you leaked at this step
NSString * retrieveName()
{
NSString *tmpStr = [[NSString alloc] initWithString "StackOverFlow"]; // retain count is 1
return tmpStr; // tmpStr returned with retain count of 1
}
Now here is the code fixed
- (IBAction)btnsecondClicked:(id)sender {
NSString *myname;
myname = retrieveName(); // retain count = 1 and the object is the autorelease pool
}// you exited the function, autorelease pool automatically drained, the object is released, no leak
NSString * retrieveName()
{
NSString *tmpStr = [[NSString alloc] initWithString "StackOverFlow"];
return [tmpStr autorelease]; // the object with retain count=1, and added to releasePool
}

Related

Assigning object to weak reference in Objective-C?

According to ARC in iOS, an object must have at least one strong reference to stay in memory, when there is no strong reference (ie. reference count becomes 0), the object will be deallocated from memory and we will have no longer access to the object.
But I am getting strange behavior in my code.
I am assigning to weak reference NSString in code,
when I write [[NSString alloc] init]; Xcode give warning .
__weak NSString *str;
str = [[NSString alloc] init];
Assigning retained object to weak property; object will be released after assignment.
if I do like this, Xcode doesn't gives any warning,
__weak NSString *str;
str = #"abcd";
NSLog(#"%#", str);
Output:
abcd
My Question is:
Why it is printing "abcd" as output. even if str is a weak reference variable. Who is keeping this NSString object which value is "abcd" in memory?
When you say str = #"abcd", you're not using a code pattern that the compiler recognizes as returning a newly-allocated object, so you don't trigger the warning about a direct assignment of a new object to a __weak variable.
Furthermore, a string literal like #"abcd" is stored in your program's executable file. It's never deallocated. The retain and release operations don't actually change its retain count. Its retain count is set to a magic number indicating an immortal object. So your __weak variable str doesn't actually get set to nil, because the object it references doesn't get deallocated. That's why it prints abcd.
In fact, clang specifically suppresses a warning if you assign a string literal (as opposed to some other kind of literal like an array literal #[a, b, c]). See the comment in the clang source code:
static bool checkUnsafeAssignLiteral(Sema &S, SourceLocation Loc,
Expr *RHS, bool isProperty) {
// Check if RHS is an Objective-C object literal, which also can get
// immediately zapped in a weak reference. Note that we explicitly
// allow ObjCStringLiterals, since those are designed to never really die.
RHS = RHS->IgnoreParenImpCasts();
// This enum needs to match with the 'select' in
// warn_objc_arc_literal_assign (off-by-1).
Sema::ObjCLiteralKind Kind = S.CheckLiteralKind(RHS);
if (Kind == Sema::LK_String || Kind == Sema::LK_None)
return false;
S.Diag(Loc, diag::warn_arc_literal_assign)
<< (unsigned) Kind
<< (isProperty ? 0 : 1)
<< RHS->getSourceRange();
return true;
}
So if we change the type to NSArray and use an array literal, we get a warning:
Moving on… You get the warning when you say str = [[NSString alloc] init] because the compiler recognizes that [[NSString alloc] init] is a code pattern that typically returns a new object.
However, in the particular case of [[NSString alloc] init], you'll discover that str again doesn't get set to nil. That's because -[NSString init] is special-cased to return a global empty-string object. It doesn't actually make a new object on each call.
__weak NSString *str;
str = [[NSString alloc] init];
NSLog(#"%ld %p [%#]", CFGetRetainCount((__bridge CFTypeRef)str), str, str);
Output:
2018-01-24 01:00:22.963109-0600 test[3668:166594] 1152921504606846975 0x7fffe55b19c0 []
That 1152921504606846975 is the magic retain count indicating an immortal object.
#define TLog(_var) ({ NSString *name = ##_var; NSLog(#"%#: %# -> %p: %# retainCount:%ld", name, [_var class], _var, _var, CFGetRetainCount((__bridge CFTypeRef)(_var))); })
__weak NSString *str;
str = #"abcd";
NSLog(#"%#",str
);
TLog(str);
After debug with your code I found that [str class] is NSCFConstantString and it's retainCount is 1152921504606846975.
for the retainCount in Objective-C, If the object's retainCount equals 1152921504606846975, it means "unlimited retainCount", this object can not be released though it is assigning to weak reference.
All __NSCFConstantString object's retainCount is 1152921504606846975, which means __NSCFConstantString will not be released whether it is __weak. The NSString created using the *str = #"abcd"; will be the same object if they are same value whether how many times to be written.

stringWithFormat and initWithFormat result different values in ARC

I am new to objective C and iOS. I am confused with 2 resulting values when using NSString stringWithFormat and initWithFormat like bellow:
NSString* str0 = #"Hello";
__weak NSString* str1 = [[NSString alloc] initWithFormat:#"%#", str0 ]; // warning: Assigning retained object to weak variable; object will be released after assignment
__weak NSString* str2 = [NSString stringWithFormat:#"%#",str0];
NSLog(#"Result: str0 %#, str1 %#, str2 %#", str0, str1, str2);
Output: Result: str0 Hello, str1 (null), str2 Hello
Looking around network, the answers for these callers are same under ARC example: stringWithFormat vs initWithFormat under ARC
However with above code, the str2 seems to not meaning regardless weak or strong here, i.e. I can remove __weak of str2 declaration and makes same result.
My concern is that, if the creation of string by stringWithFormat is owned by framework (or by some other way out of scope of user application)?
The str1 is null, because you only have weak reference to the string, so ARC may deallocate it immediately because you have no strong references to it. In fact, compiler may even warn you of this:
warning: assigning retained object to weak variable; object will be released after assignment.
The str2 is Hello because stringWithFormat creates and "autorelease" object (an object with no strong references, but that is not deallocated until the pool is drained, i.e. after you yield back to the OS). It's not "owned by the framework", but merely hasn't be deallocated yet.
Note, looking at memory management with NSString can sometimes be problematic (especially when dealing with string literals) because there are internal optimizations that sometimes affect its memory management, but these results you show us are precisely what you'd expect.
Given the atypical NSString memory management, you may want to observe this pattern using your own, custom object:
#interface CustomObject: NSObject
+ (instancetype)customObject;
#end
#implementation CustomObject
+ (instancetype)customObject {
return [[self alloc] init];
}
#end
And
__weak CustomObject *obj1 = [[CustomObject alloc] init];
__weak CustomObject *obj2 = [CustomObject customObject];
NSLog(#"obj1=%#; obj2=%#", obj1, obj2);
You will see that obj1 will consistently be nil in this case, but obj2 is not. The basic rule of memory management is that you own any object whose names start with “alloc”, “new”, “copy”, or “mutableCopy”. Thus, these objects have ownership transferred to you and ARC will release them for you (i.e. you only have one weak reference, so it's immediately released). Objects whose names start with anything besides those prefixes, have not passed ownership to you (and thus, in Objective-C, have been passed to your app as autorelease objects that will be deallocated if there are no strong references when the pool is drained.
To the root of your question, whether the object is "owned by the framework", the answer is generally no, but there are exceptions. For example NSString has some optimizations that keeps string references around. Likewise there are UIImage methods, notably imageNamed that cache images. Etc.
But, generally, you shouldn't worry about what the OS is doing. Just make sure you resolve your own strong references and let the OS do what it will do. Generally, if it does caching, these caches are purged upon memory pressure, anyway.
My answer to your question
If you want to have a weak attribute to a property someone should have
already retained it
.h
#property (nonatomic, weak) NSString *str1;
#property (nonatomic, weak) NSString *str2;
.m
#synthesize str1,str2;
-(void)viewDidLoad
{
NSString* str0 = #"Hello";
NSString* str1 = [[NSString alloc] initWithFormat:#"%#", str0 ];
NSString* str2 = [NSString stringWithFormat:#"%#",str0];
NSLog(#"Result: str0 %#, str1 %#, str2 %#", str0, str1, str2);
}
Output
Result: str0 Hello, str1 Hello, str2 Hello
Graver answer here
Detailed Explanation from Apple Forum Document
The difference is in how the return values are memory-managed.
alloc/initWithFormat: returns a retained string that you will have to
release or autorelease yourself. stringWithFormat: returns a string
that has already been autoreleased. (An autoreleased object will be
released when the current autorelease pool disappears; that usually
happens right before the next event is processed.)
Which you should use depends on what you're doing with the string. If
it's a temporary string, if it's going to be stored inside another
object, or if it's going to be stored in your own object using the
"self.property" syntax, use stringWithFormat:; if it's going to be
assigned to a global, static or instance variable (without using
"self.property"), use alloc/initWithFormat:.
In your case, you could go either way. stringWithFormat: would allow
you to remove the explicit release call, but autoreleasing is also
very slightly slower than releasing. It's up to you to decide whether
you want your code to be smaller and simpler or longer and faster.
A weak variable does not hold a reference to an object. The weak variable will be set to nil when the object is deallocated. Since you hold no reference elsewhere, that could happen at any time.
On the other hand, iOS is free to hold other references as it likes. So there is no guarantee that the weak variable will be set to nil. Therefore, according to your code, each variable may be nil, or may be not nil and have the value "Hello".
And that's what you got. Each variable can be set to nil or contain "Hello", and that's what happened.
#gnasher729 : I expected to know in which case the weak/strong pointer to NSString stringWithFormat use correct or not, while it is very different with NSString alloc, init.
I think that to understand it clearly that would help to make sure when and how I could use properly.
By the way, I agreed with #Rob and #user3182143 that NSString stringWithFormat results an autoreleased object.
To prove that, I did change to force release that object and it now is pretty clear:
NSString* str0 = #"Hello";
__weak NSString* str1 = [[NSString alloc] initWithFormat:#"%#", str0 ];
__weak NSString* str2_weak = nil;
NSString* str2 = nil;
#autoreleasepool {
str2_weak = [NSString stringWithFormat:#"%#",str0];
str2 = [NSString stringWithFormat:#"%#",str0];
}
NSLog(#"Result: str0 %#, str1 %#, str2_weak %# str2 %#", str0, str1, str2_weak, str2);
Result: str0 Hello, str1 (null), str2_weak (null) str2 Hello
with above modified code, an autoreleasepool block to cover the result of stringWithFormat, str2_weak keep a weak reference to the autoreleased object hence it shall be null after the block; str2 actually keeps own the string hence shall be not released.
The output is now 'make sense' to me:

IOS about weak and strong, what's the result should be? and constant declare

there are two properties like below
#import <Foundation/Foundation.h>
#interface Contact : NSObject
#property(nonatomic, strong)NSDate *birthDay;
#property(nonatomic, weak)NSDate *birthDay1;
- (void)testWeakProperty;
#end
on implementation file as:
- (void)testWeakProperty {
self.birthDay = [NSDate dateWithTimeIntervalSinceNow:0];
self.birthDay1 = self.birthDay;
self.birthDay = nil;
NSLog(#"_birthday1 is %#, %#", self.birthDay1 , self.birthDay);
}
why the result is not _birthday1 is (null), (null)?
I found that
iOS ARC - weak and strong properties.
if self.birthDay is constant, it will not be deallocated. but there is [NSDate dateWithTimeIntervalSinceNow:0],
now I want to know if the return value is constant and how to verify declare result is constant and a variable.
The key here is that you're dealing with an autorelease object. If a method name starts with init, copy, mutableCopy or new, you'll receive a non-autorelease object. This is not the case here (you are using dateWithTimeIntervalSinceNow) and as a result, you'll receive an autorelease object.
Thus, you are instantiating an autorelease object and therefore it will not be deallocated until the autorelease pool is drained. And your weak reference will not be nil-ed until the object is deallocated. The deallocation of autorelease objects happens when your app yields back to the run loop (or you explicitly create your own autorelease pool).
This not a question of the object being "a constant". And that other question you reference is discussing NSString which, being heavily optimized, does not conform to traditional object memory management rules.
You can change the behavior by explicitly adding your own autorelease pool, which will cause the object to be deallocated when the pool is drained at the end of the #autoreleasepool block, and you'll see your (null), (null) response:
#autoreleasepool {
self.birthDay = [NSDate dateWithTimeIntervalSinceNow:0];
self.birthDay1 = self.birthDay;
self.birthDay = nil;
}
NSLog(#"_birthday1 is %#, %#", self.birthDay1 , self.birthDay);
You can also use a non-autorelease object (e.g. use a method whose name starts with init) and this non-autorelease object will be deallocated immediately after being set to nil:
self.birthDay = [[NSDate alloc] initWithTimeIntervalSinceNow:0];
self.birthDay1 = self.birthDay;
self.birthDay = nil;
NSLog(#"_birthday1 is %#, %#", self.birthDay1 , self.birthDay);
This will also show you (null), (null).
As Rob explaining, the important point is the fact you are using an auto-released object.
Just a small precision about his explanation, [NSDate date...] is in fact a short (convenience) version of :
[[[NSDate alloc] initWith...] autorelease]
Which behave differently than an non-autoreleased instance:
[[NSDate alloc] initWith...]

Strong and Weak attribute in iOS clarification

NSString *strongObj = [[NSString alloc] init]; //alloc and initialze a new instance
strongObj = #"some value"; //set value to a instance
__weak NSString *weakObj = strongObj; //refer strong pointer to weak obj
strongObj = nil; //set strong object to nil and remove it from memory
strongObj = #"some value 2"; //assign a different value to strong obj
weakObj ; // weak obj still holds // #"some value" // this value event i've set the week obj pointer to nil
pls look at the above code and comments, the comments are my views/assumptions. Pls clarify.
Thanks
Although you are creating a strongObj instance, you are actually not using the same instance, but are reassigning the pointer to the string literal #"some value", whatever address that is. It is by no means the same instance that you allocate on the first line of your code.
Now when you assign weakObj, you will actually point it to the same string literal #"some value".
What basically happens is that weakObj is not following the strongObj, but it is following the string literal, which is not deallocated. That is why you still see "some value" in there while strongObj has been set to nil.
String literals are always alive and are never deallocated in runtime. Weak pointer is nullified when memory on which it points is deallocated, so you incorrectly expect your weakObj to be nullified.
To make it work, instead of literal strings you should use
[[NSString alloc] initWithFormat:#"some value %d", 1];
e. g.
NSString *strongObj = [[NSString alloc] initWithFormat:#"some value %d", 1]; //alloc and initialze a new instance
__weak NSString *weakObj = strongObj; //refer strong pointer to weak obj
strongObj = nil; //set strong object to nil and remove it from memory
weakObj ;

In ARC, what happens to the memory of an object that is reinitialized?

Let's say I have a method called test.
test{
NSString *answer = [[NSString alloc] initWithString:#"VALUE 1"];
answer = [[NSString alloc] initWithString:#"VALUE 2"];
}
When answer got reinitialized, what happens to the memory of the first initialization under ARC?
The first string is released (the string which was created in [[NSString alloc] initWithString:#"VALUE 1"];)
answer in this case is an object with strong ownership qualification. So from the docs, this is what happens when you assign to answer:
For __strong objects, the new pointee is first retained; second, the lvalue is loaded with primitive semantics; third, the new pointee is stored into the lvalue with primitive semantics; and finally, the old pointee is released. This is not performed atomically; external synchronization must be used to make this safe in the face of concurrent loads and stores.

Resources