In Core Foundation, do you have to access objects only using references? - core-foundation

I am trying to write a bit of Objective-C (which is new for me, my background is more C++), and wanted to create a CFString like this :
CFString myString;
When I try to build my project the following error :
"'CFString' undeclared" (first use in this function)
prevents from building.
I thought I had just forgot to include the relevant header, but I cannot find which one to include. When I look into some sample code I never see "CFString" but rather "CFStringRef" objects, defined as
A reference to a CFString object.
typedef const struct __CFString *CFStringRef;
I started to suspect there is no such thing as a CFString that i can refer to in the code, but I feel I am wrong somewhere. Am I ?
Is it impossible to create CFStrings ? Is it specific to CFString or to all the structs in objective-c ?

CFStringRef is part of the Core Foundation library which is not ObjC but plain C. Core Foundation uses a runtime to create instances, this runtime will call callbacks to initialize the structs content and manages the instances memory.
This is why there is no CFString because you shouldn't create static instances on the stack but rather call the appropriate create function which will then ask the runtime for a new instance with everything already initialized for you. For CFStringRef this would be CFStringCreate(), see also: http://developer.apple.com/library/ios/#documentation/CoreFoundation/Conceptual/CFStrings/introCFStrings.html

Related

Non-ARC to ARC: Pointer to a pointer to an object (**)

I am trying to convert an iOS project into ARC.
I am using the compiler flag for some of the files.
But one of the files contains a variable declared within a method like the following:
aClass **obj;
With ARC turned off, it gives an error:
"pointer to non-const type without explicit ownership"
I could silence the warning by doing this:
aClass *__strong* obj;
Which I believe is not a good practice as far as ownership is concerned.
But the error didn't exist in non-ARC environment.
My question is simply as follows:
How would I change from non-ARC to ARC setup the declaration of the object without having to use *__strong*?
i.e., how could I declare (or make changes to declaring) aClass **obj under ARC without have to use *__strong*, which I am sure I have read somewhere it is not a good practice to do but I forgot where I read it.
And:
Why didn't it give error under non-ARC environment.
TL;DR: You probably don't want a pointer to a pointer unless you can avoid it. It's pretty poor design to do so under a system where memory is managed for you. This answer explains more: Pointer to a pointer in objective-c?.
More Details
Under non-ARC, the system leaves retain/release up to you so it doesn't matter who owns a pointer. You, the programmer, owns it. In ARC land, the system needs to know when to retain or release, and it can't always infer which class/object has ownership over a particular object. Other classes may need the reference but the class that declared it is done with the object already. Basically, the __strong tells the declaring class that it should be in charge of managing the pointer. It 'overrides' the ownership of the pointer in a way. So that's a way to get around it. The best way to get around it would be to refactor the code to not use explicitly managed memory, but how you've fixed it will work if that's not possible/too hard.

Is it ok to store any Core Foundation type in NSMutableDictionary by casting it to id?

Is there any risk in storing any Core Foundation type in NSMutableDictionary by simple casting it to id?
As CoreFoundation objects are not compatible with ARC, you need to do its release and autorelease yourself. Also you need to bridge cast it by using these, as simply casting to id may lead to some problem:
__bridge
__bridge_transfer
__bridge_retained
NS collection types are used to contains objC objects, CF types aren't objC objects. What you can do is use toll free bridging and ARC bridging where you can, but not all CF types have a corresponding class in Foundation.
I never tried but I think that you can save just the pointer of a CF object inside an NSValue and later add it to a collection, but be aware about memory management.

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.

Move from old-fashioned struct to class

I know this could be a noob question but I am a bit stucked here. I usualy makes the following to access app data in different ViewControllers: First I declare a global.h module like this
global.h
typedef struct {
NSString *appName
NSString *appVersion;
bool mode;
} structApp;
extern structApp app;
After that I declare in MainViewController.h the struct so that I can access data
#implementation ViewController
structApp app;
- (void)viewDidLoad
{
app.appVersion = #"v1.02";
}
#end
And then I include "global.h" in every ViewController.h
This way I can access globally. As far I can see this is a good implementation and I have used it in more than 20 apps. Problem starts when this struct grows in size. In those cases I see corrupted memory, nil variables that were previously loaded with data, etc.
There is a better way of making data available in all ViewController? Please give me some examples if you can.
You have two options
Use a singleton class - Refer Objective C Singleton
Declare properties in App delegate - Refer SO
You can access the app delegate from any class using:
AppDelegate *appDel = [[UIApplication sharedApplication] delegate];
As you were using extern in your structure, any object updating the same value.
In OOPS, global variables are never said Good, so you need to use a singleton pattern.
Create a singleton/shared class having all those stuffs in your structure and use it.
You should deal with struct only if you deal with primitive data (if you are in a OOP way).
app.appVersion = #"v1.02";
Make your struct pointing on dangling pointer, since you are pointing a data in a function scope (app.appVersion is only holding the pointer, not the data). So you must retain all those object values in order to make it content safe, but i must admit it is still a Q&D approach.
If you need global access to data, you can use a singleton, only if you really need strong encapsulation and control to data.
How to make a singleton
What should my Objective-C singleton look like?
You can use macro too, that way you'll can use constants string without worrying data persistency, since they will always be available into the scope you are dealing with.
If you only want to read the data and you dont need any complex data structure you can also use a settings file like
Settings.h
#define appName #"blabla"
#define appVersion #"1.01"
#define mode 1
In General using struct should work fine. There is nothing wrong with using them. If you observe weird values caused by overlapping memory or illegal re-use of it or so then your problem is somewhere else but not in using structs in principle. The extern statement could lead to such an issue.
A class is not much more than a struct too, from a memory usage perspective. If I were you I would design a class with properties where ever you have members when using a struct. And make use of them in pretty the same way.
For "global variables" I apply a singleton pattern. That is basically a class with a class method (the leading + instead of -) that makes the one and only instance of the class available. Within that method I check if the class (a class internal static reference to the same class) is already available (!= nil) and instantiate it. Sometimes I use the initialize method for that. Initialize is an objective-c typical thing. It is called only once for each class, even subclassed ones, when or before the class is used for the first time. A very good place for instantiating class variables as singletons but not portable to other programming languages.

iOS APIS - 'Reference'

In iOS, we have CGContextRef, CGFontRef and such. What do 'Ref' indicate here? Are they refernces to objects of type CGContext, CGFont ? I do not understand this particular concept. Where can I look for the explanation of this concept?
Any help appreiated,
As far as I know, CGContextRef, CGFontRef and such are pointer types (typedefs) to plain C structures, not to Objective-C objects, and they are coming from older C frameworks of Mac OS X. See CGContext reference, CGFont reference, Core Foundation Design Concepts and Memory Management Programming Guide for Core Foundation. Because those *Ref objects are ``toll-free bridged'' with the Objective-C Cocoa framework, you can substitute them for Cocoa objects in function arguments, and vice versa (3). They have their own rules for memory management (4). I myself got a first brief but mostly sufficient explanation of those Core Foundation objects and frameworks by watching the Stanford iPhone Programming class videos (see also the class' site).
Hope I gave you some pointers to start with.
Cmd+Click on the desired type:
/* The type used to represent a CoreGraphics font. */
typedef struct CGFont *CGFontRef;
There is a struct CGFont. typedef keyword makes alias CGFontRef for this struct. 'Ref' indicates that it's a pointer.

Resources