Objective-C ARC and __weak for NSString - ios

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.

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:

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 ;

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.

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