CGContextRef/Objective C to CGContext/Swift confusion [duplicate] - objective-c

I'm using an Objective-C class in my Swift project via a bridging header. The method signature looks something like this:
- (CFArrayRef)someMethod:(someType)someParameter;
I started by getting an instance of the class, calling the method, and storing the value:
var myInstance = MyClassWithThatMethod();
var cfArr = myInstance.someMethod(someValue);
Then try to get a value in the array:
var valueInArrayThatIWant = CFArrayGetValueAtIndex(cfArr, 0);
However I get the error Unmanaged<CFArray>' is not identical to 'CFArray'. What does Unmanaged<CFArray> even mean?
I looked through How to convert CFArray to Swift Array? but I don't need to convert the array to a swift array (however that would be nice). I just need to be able to get values from the array.
I have also tried the method of passing the CFArray into a function outlined in this answer:
func doSomeStuffOnArray(myArray: NSArray) {
}
However I get a similar error when using it:
doSomeStuffOnArray(cfArr); // Unmanaged<CFArray>' is not identical to 'NSArray'
I am using CFArray because I need to store an array of CGPathRef, which cannot be stored in NSArray.
So how am I supposed to use CFArray in Swift?

As explained in
Working with Core Foundation Types, there are two possible solutions when
you return a Core Foundation object from your own function that is imported in Swift:
Annotate the function with CF_RETURNS_RETAINED or CF_RETURNS_NOT_RETAINED.
In your case:
- (CFArrayRef)someMethod:(someType)someParameter CF_RETURNS_NOT_RETAINED;
Or convert the unmanaged object to a memory managed object with takeUnretainedValue() or takeRetainedValue() in Swift. In your case:
var cfArr = myInstance.someMethod(someValue).takeUnretainedValue()

An Unmanaged is a wrapper for an actual CF value. (Sort of like an optional.) It's there because ARC can't tell from looking at the declaration of someMethod: whether that method retains the value it returns.
You unwrap an Unmanaged by telling ARC what memory management policy to use for the value inside. If someMethod calls CFRetain on its return value:
let cfArr = myInstance.someMethod(someValue).takeRetainedValue()
If it doesn't:
let cfArr = myInstance.someMethod(someValue).takeUnretainedValue()
After you do that, cfArr is a CFArray, so you can use the bridging tricks from the other questions you linked to for accessing it like a Swift array.
If you own the code for someMethod you can change it a bit to not need this. There's a couple of options for that:
Annotate with CF_RETURNS_RETAINED or CF_RETURNS_NOT_RETAINED to tell the compiler what memory behavior is needed
Since it's an ObjC method, bridge to NSArray and return that--it'll automatically become an [AnyObject] array in Swift.

Related

Why is NSArray mutable when used from Swift?

I have an objective-c header with the following property
#property (nullable, nonatomic, strong) NSArray<CustomObject *> *customObjects;
If I create a swift extension of that class I can now remove objects from the NSArray:
self.customObjects?.remove(at: 0)
Also if I do
print(type(of: self.customObjects))
I get:
Array<CustomObject>
Aren't NSArrays immutable ? Does Swift create a shallow copy whenever we edit it?
Your property is (implicitly) declared readwrite in ObjC. This means you can change the property writing a new NSArray instance that replaces the old (in which case the new instance's constants might be derived by first reading the other NSArray instance that's the existing value of the property):
NSArray *currentObjects = self.customObjects;
// one of many ways to derive one immutable array from another:
NSArray *newArray = [currentObjects subarrayWithRange:NSMakeRange(1, currentObjects.count - 1)];
self.customObjects = newArray;
In Swift, your property comes across as a Swift.Array (that is, the Array type from the Swift standard library), which is a value type. Every assignment semantically creates a copy. (The expensive work of performing the copy can be deferred, using a "copy on write" pattern. Arrays of reference types, like objects, copy references instead of storage, so it's essentially a "shallow copy".)
Mutating operations do this, too:
let currentObjects1 = self.customObjects
currentObjects1.remove(0) // compile error
// currentObjects1 is a `let` constant so you can't mutate it
var currentObjects = self.customObjects
currentObjects.remove(0) // ok
print(self.customObjects.count - currentObjects.count)
// this is 1, because currentObjects is a copy of customObjects
// we mutated the former but not the latter so their count is different
self.customObjects = currentObjects
// now we've replaced the original with the mutated copy just as in the ObjC example
When you have a readwrite property in Swift, and the type of that property is a value type like Array (or is an ObjC type that's bridged to a value type, like NSArray), you can use mutating methods directly on the property. That's because calling a mutating method is semantically equivalent to reading (and copying) the existing value, mutating the copy, and then writing back the changed copy.
// all equivalent
self.customObjects.remove(0)
self.customObjects = self.customObjects.dropFirst(1)
var objects = self.customObjects; objects.remove(0); self.customObjects = objects
BTW: If you're designing the API for the ObjC class in question here, you might consider making your customObjects property nonnull — unless there's a meaningful semantic difference between an empty array and a missing array, your Swift clients will find it cumbersome needing to distinguish the two.

Do Swift arrays retain their elements?

I'm porting one part of my objective-c framework where I had my custom MyNotificationCenter class for observing purposes.
The class had a property of type NSArray with all observables which are interested in notifications.
In objective-c, an array retains its elements, and that is unneeded because observer may not exist anymore at the point when center tries to notify him, and you don't want to have retain cycle.
Therefore I was using this block of code which kept all the items in the array without retaining them:
_observers = CFBridgingRelease(CFArrayCreateMutable(NULL, 0, NULL));
I know Swift is a different beast, however is there such concept in Swift?
Yes, an Array object in Swift retains its elements.
From the Apple Documentation:
Swift’s Array type is bridged to Foundation’s NSArray class.
so it has the same behavior of NSArray.
Reading your ObjectiveC code, what you want to achieve is to have an NSArray-like class that doesn't retain elements. This can be also achieved in another way using NSHashTable:
NSHashTable *array = [NSHashTable weakObjectsHashTable];
The NSHashTable has almost the same interface as the normal NSSet (NSHashTable is modeled after NSSet), so you should be able to replace your NSArray value with NSHashTable value with small changes.
Yes, Swift arrays do retain their elements
Let's define a simple class
class Foo {
init() {
print("Hello!")
}
deinit {
print("Goodbye...")
}
}
And now let's try this code
var list = [Foo()]
print(1)
list.removeAll()
This is the output
Hello!
1
Goodbye...
As you can see the Foo object is retained in memory until it is removed from the array.
Possible solution in Swift
You could create your own WeakArray struct in Swift where each element is wrapped into a class with a weak reference to the element. The class object is then inserted into the array.

Is there a way to reflectively call a function in Objective-C from a string?

Are there any Objective-C runtime functions that will allow me to get a function (or block) pointer from a string identifying the function? I need some way to dynamically find and invoke a function or static method based on some form of string identifying it.
Ideally this function should be able to exist in any dynamically loaded library.
Looking at Objective-C Runtime Reference, the best bet looks like class_getClassMethod, but there don't appear to be any function-related functions in this reference. Are there other raw C ways of getting a pointer to a function by name?
if you want to invoke some static objc method, you can make it as a class method of a class
#interface MyClas : NSObject
+ (int)doWork;
#end
and call the method by
[[MyClass class] performSelector:NSSelectorFromString(#"doWork")];
if you real want to work with C-style function pointer, you can check dlsym()
dlsym() returns the address of the code or data location specified by
the null-terminated character
string symbol. Which libraries and bundles are searched depends on the handle
parameter If dlsym() is called with the special handle RTLD_DEFAULT,
then all mach-o images in the process
(except those loaded with dlopen(xxx, RTLD_LOCAL)) are searched in the order they were loaded. This
can be a costly search and should be avoided.
so you can use it to find the function pointer base on asymbol name
not sure why you want to do this, sometimes use function table can do
typedef struct {
char *name,
void *fptr // function pointer
} FuncEntry;
FuncEntry table[] = {
{"method", method},
{"method2", method2},
}
// search the table and compare the name to locate function, you get the idea
If you know method signature you can create selector to it with NSSelectorFromString function, e.g.:
SEL selector = NSSelectorFromString(#"doWork");
[worker performSelector:selector];
You may be able to do what you want with libffi. But unless you are doing something like create your own scripting language or something like that where you need to do this sort of thing a lot. It is probable overkill
I've wondered the SAME thing.. and I guess, after having researched it a bit.. there is NOT a "standard C" way to do such a thing.. (gasp).. but to the rescue? Objective C blocks!
An anonymous function.. that can be OUTSIDE any #implementation, etc...
void doCFunction() { printf("You called me by Name!"); }
Then, in your objective-C method… you can somehow "get" the name, and "call" the function...
NSDictionary *functionDict = #{ #"aName" : ^{ doCFunction(); } };
NSString *theName = #"aName";
((void (^)()) functionDict[theName] )();
Result: You called me by Name!
Loves it! 👓 ⌘ 🐻

getting return value type of an instance method in runtime

I want get the return value class of an instance in runtime. The thing it's that I have a SEL type var where I store a selector. I have a variable named id _instance that points to an instance that I know it performs the selector. Before perform the method I want to know if I have to do:
NSObject* returnValue=[_instance performSelector:_selector withObject:params.params];
or:
[_instance performSelector:_selector withObject:params.params];
I have read a post where someone explain the way to have that with objective-c runtime:
Method m = class_getClassMethod([_instance class], _selector);
char ret[256];
method_getReturnType(m, ret, 256);
NSLog(#"Return type: %s", ret);
But the outputs is nothing like ret is empty.
Really it can be enough to know if it's a void or have a return type but I don't know where to search. I have read the objective-c runtime reference but the only thing I found is the method_getReturnType.... Any idea?
If you're looking for an instance method, you need to use class_getInstanceMethod rather than class_getClassMethod. Class methods and instance methods are obviously different things.
After searching a while I found the library that uses Spotify for this kind of stuff, the name is MAObjcRuntime and you can found it here

Function pointer problem in Objective-C

So I am trying to store a series of methods in an array (if that made sense).
void *pointer[3];
pointer[0] = &[self rotate];
pointer[1] = &[self move];
pointer[2] = &[self attack];
//...
What I am trying to do is have an array of stuff and based on the type of the object in the array, a certain method is invoked. And instead of having a bunch of if statement saying something like:
if ([[myArray objectAtIndex:0] type] == robot]) {
//Do what robots do...
}
else if (...) {
}
else {
}
And having this in a timer I was hoping to make it something like this:
pointer[[[myArray objectAtIndex:0] type]]; //This should invoke the appropriate method stored in the pointer.
Right now the code above says (the very first block of code):
Lvalue required as unary '&' operand.
If you need any clarification just ask.
Also, just to let you know all the method I am calling are type void and don't have any parameters.
You can't just make a function pointer out of an Objective-C function using the & Operator.
You'll want to look into:
#selector
NSInvocation
Blocks
Any of these can do what you want. Definitely read about selectors (the #selector compiler directive and the SEL type) if you're unfamiliar with that (it's a basic concept that you'll need a lot). Blocks are fairly new (available since Mac OS X 10.6 and iOS 4) and they'll save you a ton of work where you would have needed target/selector, NSInvocation or callback functions on earlier versions of Mac OS X and iOS.
Use function pointers if you need to pass around references to C functions but when working with methods on Objective-C objects you should really use selectors and the SEL type.
Your code would then be something like:
SEL selectors[3];
selectors[0] = #selector(rotate);
selectors[1] = #selector(move);
selectors[2] = #selector(attack);
...
[self performSelector:selectors[n]];