stringWithFormat and initWithFormat result different values in ARC - ios

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:

Related

"Assigning retained object to weak property" with init?

While playing around with ARC, I noticed that when I have a weak String:
#property (weak, nonatomic) NSString *myString;
And then if I were to do this:
self.myString = [[NSString alloc] init];
or even
[[NSString alloc] initWithString:#""]
Xcode immediately warns me "Assigning retained object to weak property; object will be released after assignment". And while I can understand that, because its reference count is 0, why does this work with no warnings:
self.myString = #"";
What difference does it make for ARC?
Because when you have a weak property, ARC does not increase the reference count...
So when you write:
self.myString = [[NSString alloc] init];
ARC adds a release just after, because it is the same as writing:
[[NSString alloc] init];
The main difference with #"" it is that it's a static string, in a way retained somewhere else...
Each time you use #"" it points to the same object.
Edit: The difference between #"" and [[NSString alloc] initWithString:#""] is that the first is a static string and is processed at compile time. If it is used elsewhere the other use will point to the same static string. The second, is processed at runtime. It really creates a new object, with its retain count and so on... That's why ARC does its job for the created instance (you specifically call a alloc) and why it does not care for static strings.
For ' Ok, so why does it show the same warning if I do this: [[NSString alloc] initWithString:#""] ? '
When you use [[NSString alloc] initWithString:#""], system will create a new string with #"" and it will be allocated in memory heap.

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.

Objective-C ARC and __weak for NSString

NSString __weak *string = [[NSString alloc] initWithFormat:#"First Name: %#", #"Braj"];
NSLog(#"string:%#", string);
NSString __weak *string2=#"Hello";
NSLog(#"string:%#", string2);
NSString __weak *string3 =[[NSString alloc]initWithString:#"Braj"];
NSLog(#"string:%#",string3);
Here, first string gives output null and other two string objects gives ans as Hello and Braj respectively.
I am confused here how to deal __weak reference.
"weak" means the pointer variable doesn't hold a reference to the object, so the pointer allows the object to be deallocated. When that happens, the pointer is set to nil.
So the first NSLog does what you should expect. There is no strong reference to the object, so it becomes nil immediately.
In the second case, you have a string literal. String literals are different: They actually never go away. They are created using some clever trickery which means no memory would be saved if they were deallocated.
The third case: [[NSString alloc] initWithString:aString] is clever. It doesn't actually allocate a new string if it isn't necessary! If aString is an immutable string, then the result is aString and not a new object. You passed a string literal to it, so the result is that string literal. Back to case 2 :-)
weak references can become nil when someone else releases the last strong reference to an object. But your code never knows who might hold a strong reference (behind the scenes), so you can never rely on a weak reference becoming nil.

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...]

iOS why does this property needs to be strong

I have a property which I thought could be weak. But it doesn't display unless it is set to strong.
This:
- (void) setTimeAndLocation:(Message *)activity{
__weak NSString *time = [[[activity getPropertyByPath:#"StartTime"] value] substringWithRange:NSMakeRange(0, 5)];
NSLog(#"Time: %#", time); // null
__strong NSString *time = [[[activity getPropertyByPath:#"StartTime"] value] substringWithRange:NSMakeRange(0, 5)];
NSLog(#"Time: %#", time); // works, 20:30
__weak NSString *time = [[activity getPropertyByPath:#"StartTime"] value];
NSLog(#"Time: %#", time); // works, 20:30:00
}
Is this because substring creates a new string or something like that? I know I don't have to add the __weak or __strong but this is for me very helpful to understand what everything does
time is a local variable, not a property.
Generally, all local variables are __strong (which is the default when you omit the modifier) because they are automatically disposed when they go out of scope.
You never declare a local variable __weak for a newly created object, because the object will be destroyed as soon as it is created. I suspect that substringWithRange: creates a new object, as you mention.
The fact that the second one works is misleading. When you declare a local variable __weak you have no guarantees that it will be available unless you know you are accessing an object that is strongly retained elsewhere. The variable should be __strong (no modifier) in both cases.
__weak is used when you want to create a weak local variable of a previously created object that is strongly referenced elsewhere. Typically, you use __weak variables if you wish to avoid retain cycles inside retained blocks.

Resources