Immutable Array/Dictionary Initialization [duplicate] - ios

This question already has answers here:
How to fill NSArray in compile time?
(4 answers)
Closed 8 years ago.
If I initialize an NSArray as follows:
- (void) myMethod
{
NSArray *array = [NSArray arrayWithObjects:#"A","B","C",nil];
// DO SOME STUFF HERE
return;
}
Is this immutable array initialized at compile time or at run time? Same with NSDictionary. I'm thinking it must be at compile time but just wondering.

No… It would not be created in compile time… It would be created in runtime when the Method is being called.
By Immutability, it means that You cannot edit size of the array after once initializing it.
refer to this Link for more info about Object Mutability… Let me know if more info needed.. :)

Following code is what you want?
static NSString *strArray[] = {#"A", #"B", #"C"};
To use it with index like this: stringArray[index];

No, Method call arrayWithObjects: is not possible at compile time. During compilation, it just check that syntax, unless that variable would be constants or statics. Macros and constants are initialized at compile time. See this example below.
You could initialize directly, if the size is known as below(same example also posted by #simalone)
int num[5] = {2,8,7,6,0};

Related

Do we need to deallocate CFArray?

I have a CFMutableArray that I created using CFArrayCreateMutable.
I just need to know whether I need to deallocate this array by myself, or is it already taken care by the ARC? If I need to deallocate this, how can I, since I didn't find any function like CFArrayRelease?
All Core Foundation objects that were allocated/copied/retained by user should be released by the user. To release the CFMutableArray, you use CFRelease() function.
CFMutableArrayRef ar = CFArrayCreateMutable(kCFAllocatorDefault, capacity, NULL);
// some code
CFRelease(ar);
More information here:
https://developer.apple.com/library/ios/documentation/CoreFoundation/Conceptual/CFMemoryMgmt/Concepts/Ownership.html#//apple_ref/doc/uid/20001148-CJBEJBHH
https://developer.apple.com/library/ios/documentation/CoreFoundation/Conceptual/CFMemoryMgmt/Articles/lifecycle.html#//apple_ref/doc/uid/TP40002439-SW1
Yes, we need.
You have two options:
Transfer ownership to ARC while creating the item by casting the type to an Objective-C object.
NSMutableArray *array = (NSMutableArray *)CFBridgingRelease(CFArrayCreateMutable … )
Or release the object later
CFRelease(cfMutableArray)

Value stored to NSString during its initialization is never read

In my iOS app I have following code:
case SASpeechSubCase03:
{
SAActivity currentActivity = self.mediator.selectedActivity;
NSString *sActivity = NSLocalizedString(#"activity", #"activity");
NSString *sActivity2 = NSLocalizedString(#"another activity", #"another activity");
if(currentActivity == SAActivityWalk)
{
sActivity = NSLocalizedString(#"walk", #"walk");
sActivity2 = NSLocalizedString(#"walking", #"walking");
}
else
{
sActivity = NSLocalizedString(#"run", #"run");
sActivity2 = NSLocalizedString(#"jogging", #"jogging");
}
return [NSString stringWithFormat:speech.text, sActivity, sActivity2];
break;
}
When I run bots on it, it gave me following warning:
Bot Issue: analyzerWarning. Dead store.
Issue: Value stored to 'sActivity' during its initialization is never read.
File: SAAnnouncementService.m.
Integration Number: 42.
Description: Value stored to 'sActivity' during its initialization is never read.
Bot Issue: analyzerWarning. Dead store.
Issue: Value stored to 'sActivity2' during its initialization is never read.
File: SAAnnouncementService.m.
Integration Number: 42.
Description: Value stored to 'sActivity2' during its initialization is never read.
Can someone tell what the problem might be here?
Any kind of help is highly appreciated!
The problem is that you initialized the variables and then directly started the if-else blocks, without using, i.e. reading, the initial values.
When execution gets to the if-else blocks, it will definitely be assigned a new value, no matter what value it was before.
With the following line :
NSString *sActivity = NSLocalizedString(#"activity", #"activity");
NSString *sActivity2 = NSLocalizedString(#"another activity", #"another activity");
You are assigning string values to the sActivity and sActivity2 objects.
Then, these two values are modified in either if or else statement.
But, as the static analyzer mentions, the initial values of these objects (#"activity" and #"another activity") were never read before the second assignment (in if / else statement).
To avoid this warning you can replace the two lines above, by :
NSString *sActivity = nil;
NSString *sActivity2 = nil;
Hope that helps ;)
When you get a warning, the compiler tells you "what you are doing here looks like nonsense, and is most likely not what you want".
Look at these two statements:
NSString *sActivity = NSLocalizedString(#"activity", #"activity");
NSString *sActivity2 = NSLocalizedString(#"another activity", #"another activity");
Does the assignment serve any purpose? It doesn't look like it. So the compiler thinks "either the guy made a rather expensive call that is completely pointless, or he actually intended to use the result of NSLocalizedString but stored it in the wrong place. "
Since the compiler assumes that people don't do pointless things, it assumes that there is a bug in your code and tells you about it. It's the kind of thing where a human reviewing your code would stop and ask you what you were intending to do there.
In your codes, sActivity would be set to either walk or run within IF/ELSE, so that the value set for sActivity this line
NSString *sActivity = NSLocalizedString(#"activity", #"activity");
would never be read. It might not cause error but analyzer reminded you about this superfluous initialization. Try NSString *sActivity=nil;, see if the warning could be turned down.
You are not using sActivity in if-else blocks, you are simply assigning it values based on decision, So either take it nil string like
sActivity = nil;
or like
NSString *sActivity;
to remove waring .

Not allowed to call release on NSString [duplicate]

This question already has answers here:
Release a NSMutableArray when using ARC
(2 answers)
Closed 9 years ago.
I have a string that I generate with JSON data from an URL
NSString *strResult = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
This code is inside viewDidLoad method. I want to release the string before I exit the method to avoid any memory leak, and I do this according to this post.
[strResult release];
However, xCode does not allow me by giving error: ARC forbids explicit send message of 'release'.
Anybody knows why? I tried to google it but no luck. I am new to iOS programming, and I have tried to google it before I asked. So any help will be appreciated.
ARC automatically adds the methods to deallocate objects, at compile time, for you.

IOS: Release for NSString is not working as expected

I found a strange behavior with NSString. I tried to run the below code and noticed this.
NSString *str = [[NSString alloc] initwithstring : #"hello"];
[str release];
NSLog(#" Print the value : %#", str);
Here, in the third line app should crash because we are accessing an object which is released. But it is printing the value of str. It is not crashing. But with NSArray i observed different behavior.
NSArray *array = [[NSArray alloc] initwithobjects : #"1", #"2", nil];
[array release];
NSLog(#"Print : %#", [array objectatindex : 0]);
NSLog(#"Print : %#", [array objectatindex : 0]);
The code has two NSLog statements used for NSArray. Here after releasing when the first NSLog is executed, it is printing value. But when second NSLog is executed, app crashes. App crash is acceptable because the array accessed was released already. But it should crash when the first NSLog is executed. Not the second one.
Help me with this behaviors. How release works in these cases.
Thanks
Jithen
The first example doesn't crash because string literals are never released. The code is really:
NSString *str = #"hello";
[str release];
People get burned with string literals on memory management and mistakenly using == to compare them instead of isEqualToString:. The compiler does some optimizations that lead to misleading results.
Update:
The following code proves my point:
NSString *literal = #"foo";
NSString *second = [NSString stringWithString:literal];
NSString *third = [NSString stringWithString:#"foo"]; // <-- this gives a compiler warning for being redundant
NSLog(#"literal = %p", literal);
NSLog(#"second = %p", second);
NSLog(#"third = %p", third);
This code gives the following output:
2013-02-28 22:03:35.663 SelCast[85617:11303] literal = 0x359c
2013-02-28 22:03:35.666 SelCast[85617:11303] second = 0x359c
2013-02-28 22:03:35.668 SelCast[85617:11303] third = 0x359c
Notice that all three variable point to the same memory.
Your second example crashes at the second NSLog because at the first log, the memory where array was hasn't been re-used, but that first log causes enough activity on the heap to cause the memory to become used by something else. Then, when you try to access it again, you get a crash.
Whenever an object is deallocated and its memory marked as free, there is going to be some period of time where that memory still stores what's left of that object. During this time you can still call methods on such objects and so forth, without crashing. This time is extremely short, and if you're running a lot of threads it may not even be enough to get your method call in. So clearly, don't rely on this implementation detail for any behavior.
As others have said, regarding your first question, NSString literals aren't going to be deallocated. This is true for some other Foundation classes (NSNumber comes to mind) but is an implementation detail as well. If you need to do experiments on memory management, use an NSObject instance instead, as it will not show the unusual behaviors.
When you send a release message on an object, the object is actually not being removed from the memory. The release message simply decrements the reference count by one only. If the reference count is zero the object is marked as free. Then the system remove it from the memory. Until this deallocation happens you can access your object. Even if you release the object your object pointer still points to the object unless you are assigning nil to the pointer.
The first example doesn't crash because string literals are never released. Where the second totally depends on release and retain counter.
Read this article. Its contains short-and-sweet explanation for your query
You Should read this apple guideline
You seem to assume that release should destroy the object immediately. I don't think that's the guarantee that the language makes. What release means is: I have finished using this object and I promise not to use it again. From that point onwards it's up to the system to decide when to actually deallocate the memory.
Any behaviour you see beyond that is not defined and may change from one version of the Objective C runtime to the next.
That's to say that the other answers that suggest the difference is string literals and re-use of memory are currently correct but assuming that the behaviour will always be like this would likely be a mistake.

Using output parameters with ARC

So I have read this question, which seems to be exactly the kind of problem I am having, but the answer in that post does not solve my problem. I am attempting to write a data serialization subclass of NSMutableData. The problematic function header looks like this:
-(void)readString:(__autoreleasing NSString **)str
I do some data manipulation in the function to get the particular bytes the correspond to the next string in the data stream, and then I call this line:
*str = [[NSString alloc] initWithData:strData encoding:NSUTF8StringEncoding];
No errors in this code. But when I try to call the function like so:
+(id) deserialize:(SerializableData *)data
{
Program *newProgram = [[Program alloc] init];
[data readString:&(newProgram->programName)];
On the line where I actually call the function, I get the following error:
Passing address of non-local object to __autoreleasing parameter for write-back
I have tried placing the __autoreleasing in front of the NSString declaration, in front of the first *, and between the two *'s, but all configurations generate the error.
Did I just miss something when reading the other question, or has something in the ARC compiler changed since the time of that post?
EDIT:
It seems that the problem is coming from the way I am trying to access the string. I can work around it by doing something like this:
NSString* temp;
[data readString&(temp)];
newProgram.programName = temp;
but I would rather have direct access to the ivar
You can't. You might gain insight from LLVM's document Automatic Reference Counting, specifically section 4.3.4. "Passing to an out parameter by writeback". However, there really isn't that much extra detail other than you can't do that (specifically, this isn't listed in the "legal forms"), which you've already figured out. Though maybe you'll find the rationale interesting.

Resources