Should I release an NSDictionary instantiated through the form #{}? - ios

I have the following code:
NSDictionary *dict = #{ #"myKey" : #"myValue" };
Should I release dict using release or autorelease?
Or I do not own the object, so I should not release it myself?
Note: I use manual reference counting (ARC is disabled).

No, you must not release a NSDictionary created with the literal syntax. The Clang documentation tells that dictionary literal expressions expand to +[NSDictionary dictionaryWithObjects:forKeys:count:], so you do not own the object.
No Objective-C literal expands to an expression creating an owning reference.

Even if you have ARC disabled (which you should have it enabled), you do not need to release it because you do not own the object. You only own the object when you created it through alloc or new.

I asked the question too early, sorry. But here's the answer:
I tried analyzing it myself, since I cannot find references (maybe because of the vague keyword #{}).
When adding autorelease to the dictionary created by #{ #"myKey" : #"myValue" }, the app crashes. I also ran the code through Xcode's Static Analyzer, and it gave a Memory issue.
So, we do not need to release objects retrieved using #{}, similar to NSString from #"".
I also tried it for NSArray using #[]. The same behavior applies.
We do not need to release them ourselves.

Related

Swift collection that has defined types and copies by reference?

In converting old projects from Objective-C to Swift, I've mostly been able to use Dictionary in place of NSMutableDictionary. But in some cases, it's a hassle or uses a lot of extra memory to have the Dictionaries copying by value.
I thought I could simply change some Dictionary collections to NSMutableDictionary to make them objects that copy by value, but I don't see a way to specify the key and value types. This works in Objective-C:
NSMutableDictionary<NSString*, NSString*> *dict = [NSMutableDictionary dictionary];
But this gives an error "Cannot specialize non-generic type 'NSMutableDictionary'" in Swift:
let dict: NSMutableDictionary<String, String> = [:]
Is there a way to specify the types so I don't have to be constantly casting the values I get out of the dictionary?
Alternatively, is there another kind of collection object that supports key and value types like Dictionary but copies by reference like NSMutableDictionary?
UPDATE
I tried using NSMapTable as suggested in the comment below. That's missing some features of NSDictionary (e.g., it doesn't conform to IteratorProtocol), so I made a subclass to try making a drop-in replacement for Dictionary. I then ran into problems making my subclass generic since Swift and Objective-C have different support for that.
Since that would either require a lot of casting (or making a different subclass for each type of data I wanted to store in the dictionary), I then tried just using NSMutableDictionary and casting all the values when I read them. Unfortunately, after all that work, I couldn't see any difference in memory usage compared to using Dictionary.
So I guess having collections that copy by value isn't really my problem. It shouldn't be since I'm never retaining anything for very long, but I didn't see these memory problems until I migrated from Objective-C. I'll have to do more testing and explore other solutions.
The Objective-C specification:
NSMutableDictionary<NSString*, NSString*>
Is not a true implementation of Generics. It simply gives hints to the compiler that the dictionary will contain strings as the keys and values and the compiler can tell you, at compile time, if you make a simple mistake.
At the end of the day, there is nothing at runtime to enforce those type specifications. An NSDictionary (mutable or not) will have id for the keys, and id for the values and the runtime format will not change. That's why you can get away with using [NSMutableDictionary dictionary] to initialize all NSDictionaries... the type spec only has meaning at compile time.
In contrast when you use a identical syntax in Swift, say Dictionary<String, Int>, you are using true generics. The runtime representation of the dictionary may change depending on what key and value types you use.
In other words, in spite of similarities in their in Syntax, the <type, type> construct in Objective-C and in Swift mean VERY different things.
In Swift's Eyes, an NSDictionary (mutable or not) is simply a NSObject, just like every other NSObject so NSDictionary<NSString, NSString> is a nonsensical use of the generic type specification syntax - you're saying you want to use generics with a type that is not a generic type (hence the error).
There is no Swift syntax (that I'm aware of) that lets you specify the type you'd like to stand in for NSObject in things like NSDictionaries and NSArrays. You're going to have to use casting.
Even in Objective-C the type specs mean nothing and it's possible to squeeze something in there that doesn't belong. Consider:
NSDictionary<NSString *, NSString *> *myDictionary = [NSMutableDictionary dictionary];
((NSMutableDictionary *)myDictionary)[[NSNumber numberWithInt: 3]] = [NSURL URLWithString: #"http://www.apple.com"];
Here I declare the dict to use Strings, then shove in a number and a URL. The only way to guard against this would be to check the types, that is to do typecasting (or at least type-checking), for each key and value. Most folks code doesn't do that because it would be a pain, but the only way to get true safety.
Swift, in contrast, focus on the safety right up front. It's one of the defining differences between Swift an Objective-C. So you have to go through the pain if you insist on using "unsafe" Objective-C types.

Is this NSString a memory leak?

NSString *pDescText = #"blablabla";
pDescText = [NSString stringWithFormat:#"%# %#",skProduct.localizedDescription,formattedPrice];
Does this produce a memory leak when I reassign pDescText in line 2?
If you are using ARC, you don't need to worry about these kinds of leaks.
If you are using MRC, you don't have a leak because:
You only need to release objects that you have a received a reference to by sending messages which contain new alloc retain or copy. In neither of these lines have you done this so you don't have an owned reference to pDescText. Furthermore, in the first line you are using a string literal, which is something that yo don't have to worry about memory management for.
And I have to say this pDescText is not a good name to use for a variable in Cocoa. We don't use hungarian notation (so the p to indicate a pointer isn't needed) and full, descriptive variable names are the norm. So instead of pDescText a more experienced Cocoa developer would use descriptiveText or even productDescription or description if that is enough for the context.
No, NSString convenience constructors return an autoreleased object.

Trying to Understand CFTree Documentation

I am trying to make a CFTree that holds strings as nodes. I am having trouble understanding the documentation for the class. Here is the link: https://developer.apple.com/library/mac/documentation/corefoundation/Reference/CFTreeRef/Reference/reference.html#//apple_ref/c/func/CFTreeSetContext
When you create a CFTree you call CFTreeCreate and pass in an allocator and a context. The allocator parameter I understand, but I don't understand the context argument.
Here are the fields you need to fill in in a context before you pass the context to CFTreeCreate:
version - this one I understand, I just make it version 0
info - Will I just set this to the NSString? Isn't that not OK because I need to use the __bridge or something? I'm kind of confused about this one
retain - Does ARC take care of retaining even though this is a Core Foundation class? I'm not sure what to put here
release - same as above
copyDescription - Not sure what the point of this field is or if I need it for what I'm trying to do.
Will I just set this to the NSString? Isn't that not OK because I need to use the __bridge or something?
If you want to do that, you'll have to do a non retaining bridging cast. Because NSString is toll free bridged with CFStringRef, in the tree, you can treat your NString as a CFStringRef and set the retain and release functions to CFRetain and CFRelease respectively - I think it should be OK, the prototypes look compatible.
Does ARC take care of retaining even though this is a Core Foundation class?
No, it doesn't, but if you set the retain and release functions as I suggested, you should be OK.
copyDescription - Not sure what the point of this field is or if I need it for what I'm trying to do
It just spits out a description, in the same way as -description does for a Cocoa object. You can leave it null, but if your info is an NSString something like this will do the trick:
CFStringRef* copyDescription(void* info)
{
return CFStringCreateCopy(someAllocator, (CFStringRef) info);
}
I haven't tried it, so it might not work.

CFStringRef to NSString ARC leaking. Why?

I have been looking around for the correct way to go from CFStringRef to NSString in ARC to avoid memory leaks and some of the main voted answers suggest:
NSString * string = (__bridge NSString *)cfString;
I am using that approach here but when profiling the app I still get a memory leak in this small method [see attached image].
So, I am not sure how to fix this. Anybody has the solution to this problem?
Thank you
So, apparently adding the CFRelease(ext) before the return fixed the leak. Problem is I don't think I fully understand the reason. I thought that the line:
NSString * extension = (__bridge NSString*)ext
Would take ownership of the Core Foundation ext string and handle the release.
Can anybody explain what is going on here exactly?
As per the de-facto "standard" Cocoa naming convention, functions that contain Create or Copy in their name return an object with a reference count of 1. You have to transfer this reference count into ARC-land so that ARC can take care of it. You use the __bridge_transfer keyword for this purpose.
NSString *string = (__bridge_transfer NSString *)cfString;
Release the ext object or use __bridge_transfer.
Let me explain this a bit in the way I understand it:
__bridge – Normal casting. The retain count of casted object is partially managed by ARC and partially manually. You need to release the existing ownership on the CF side.
__bridge_transfer – “Converts CF object to NS object.” The retain count of casted object is fully managed by ARC. Existing ownership on the CF side is disposed for you.

Is there any difference between initializing a NSDictionary using curly brackets or standard +dictionaryWithObjectsAndKeys:?

I saw an Apple sample code with a NSDictionary being initialized using #{ value:key } notation. I use to initialize a constant NSDictionary using +dictionaryWithObjectsAndKeys:
My question is:
Is there any difference between the two generated NSDictionaries? Do I need to worry about memory leaking? I'm using ARC.
All I found about it is this Apple doc, but it is related to Mac, not iOS. And the notation is #{ key = value } and not #{ value:key }.
http://developer.apple.com/legacy/mac/library/documentation/LegacyTechnologies/WebObjects/WebObjects_3.1/DevGuide/WebScript/CreatingObjects.html
A second question would be: is that safe to use this to submit the app to App Store, or would it be considered "undocumented API"?
Thanks!
I use… +dictionaryWithObjectsAndKeys: … Is there any difference between the two generated NSDictionaries?
The compiler uses +[NSDictionary dictionaryWithObjects:forKeys:count:]. So the 'gotcha' is that the parameters/values you use in these literal expression must not be nil. When you use +[NSDictionary dictionaryWithObjectsAndKeys:], the input stops when nil is encountered. It is an error to pass nil to a literal expression as a key or value to a literal expression. This may change your program (because semantics of dictionary creation through va_lists are different), but the stricter semantics would likely result in detecting bugs, more than anything.
Do I need to worry about memory leaking? I'm using ARC.
You might need an autorelease pool in some cases -- that depends on the context you create it in.
Is that safe to use this to submit the app to App Store, or would it be considered "undocumented API"?
You will need Apple-Clang 4.0 (Xcode 4.4). It is compatible with all versions of OS X and iOS:
http://developer.apple.com/library/ios/#releasenotes/ObjectiveC/ObjCAvailabilityIndex/_index.html
More details here: http://clang.llvm.org/docs/ObjectiveCLiterals.html

Resources