Objective-C: C struct in #property with custom deallocation function - ios

I have a C struct with custom allocation/deallocation functions because the struct has a dynamically-allocated nested array:
struct Cell {
int data, moreData;
};
struct Grid {
int nrows, ncols;
struct Cell* array;
};
struct Grid* AllocGrid (int nrows, int ncols) {
struct Grid* ptr = (struct Grid*) malloc (...);
// ...
ptr->array = (struct Cell*) malloc (...);
return ptr;
}
void FreeGrid (struct Grid* ptr) {
free (ptr->array);
free (ptr);
}
I want to use this struct in the UIViewController of my Objective-C app. The grid's lifespan should be the same as the controller's one.
If it were a C++ object, I would call AllocGrid() in the constructor and match it with a call to FreeGrid() in the destructor. So I tried to put the allocation in the init message and the deallocation in dealloc:
#implementation ViewController
{
struct Grid* theGrid;
}
- (id)init {
self = [super init];
if (self) {
NSLog(#"init()");
theGrid = AllocGrid(10,10);
}
return self;
}
- (void)dealloc {
NSLog(#"dealloc()");
DeallocGrid(theGrid);
theGrid = NULL;
}
#end
But the allocation is never executed and I cannot see the "dealloc" log message when running the app in the iOS simulator. I guess I could do the allocation in viewDidLoad but I feel it's not the right thing to do. Hence my question:
Question: How can I wrap the C struct in a #property and force it to use my custom AllocGrid() and DeallocGrid() functions?
Or: Is there an equivalent of a scoped_ptr in Objective-C? Or should I roll out my own?

I think putting the allocation in the viewDidLoad() is correct. In fact, there is a discussion regarding to why init() is not being called in ViewController, iPhone UIViewController init method not being called. But, it depends on your context, if you want to initialize your structure "before" the view appear, you should put your initialization in viewWillAppear. There's another interesting thread talking about the invoking order in ViewController, Order of UIViewController initialization and loading. Finally, I want to point out Objective-C is an extension of C, so the "basic" allocation/free behavior should be the same.

Related

Updating SwiftUI view from an Objective C Class

I am not experienced with IOS development but have some basic understanding to work my way through it by reading docs and tutorials.
I wanted to call Objective C code from Swift and it worked fine, now I want to do the opposite and getting confused a bit.
Basically I first call an Objective C function in the action of a Button in SwiftUI, then I want that function to update an ObservedObject in the same SwiftUI view and want the view to re-render.
I have found and followed a few resources on that, which are
https://medium.com/#iainbarclay/adding-swiftui-to-objective-c-apps-63abc3b26c33
https://pinkstone.co.uk/how-to-use-swift-classes-in-objective-c/
Swift UI view looks like
class Foo : ObservableObject {
#Published var bar = ""
}
struct ContentView: View {
#ObservedObject var baz = Foo();
// Then access later as self.baz.bar as a parameter somewhere..
What would be the right way to update bar here ?
I did the correct build settings and added #objc tags and also imported project_name-swift.h.
Implemented and modified the example in
https://medium.com/#iainbarclay/adding-swiftui-to-objective-c-apps-63abc3b26c33 but got lost a bit because of my lack of experience in these environments.
Maybe somebody can push me in the right direction.
Thank you.
Let's assume my project name is Project.
Example code :
(A code very similar to this, compiles fine and the Objective C function calls, but on the swift side I get no output to console and the text doesn't render. I would really appreciate if you point my mistakes in this, since I get very rarely involved in iOS development.)
ContentView.swift
import Foundation
import SwiftUI
var objectivec_class = Objectivec_Class()
class Foo : ObservableObject {
#Published var bar = ""
}
#objc
class BridgingClass: NSObject {
#ObservedObject var baz = Foo();
#objc func updateString(_ content: NSMutableString) {
print("This function is called from Objective C")
self.baz.bar += content as String
}
}
struct ContentView: View {
/**
* This part seems fishy to me,
* It would have been better to inject the instance of Foo here in
* BridgingClass but, couldn't figure out how to.
* This is only for showing my intention.
*/
#ObservedObject var baz = Foo();
var body: some View {
Button(action: {
objectivec_class.updateSwiftUi()
})
{
Text(self.baz.bar)
}
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
Objective C Bridging Header,
Project-Bridging-Header.h
#import "Objectivec_Class.h"
Objectivec_Class.h
#ifndef Objectivec_Class_h
#define Objectivec_Class_h
#import <Foundation/Foundation.h>
#import "Project-Swift.h"
#interface Objectivec_Class : NSObject
#property (strong, nonatomic) NSMutableString* stringWhichWillBeRendered;
#property BridgingClass *bridgingClass;
- (id) init;
- (void) updateSwiftUi;
#end
#endif /* Objectivec_Class_h */
Objectivec_Class.m
#import <Foundation/Foundation.h>
#import "Project-Swift.h"
#import "Objectivec_Class.h"
#implementation Objectivec_Class
- (id)init{
if( self = [super init] ){
_stringWhichWillBeRendered = [NSMutableString stringWithString:#""];
BridgingClass *bridgingClass = [BridgingClass new];
}
return self;
}
- (void) updateSwiftUi {
NSString *thisWillBeRendered = #"Render this string.";
[_stringWhichWillBeRendered appendString:thisWillBeRendered];
[[self bridgingClass] updateString:_stringWhichWillBeRendered];
}
#end
Try the following
#objc
class BridgingClass: NSObject {
var baz = Foo() // here !!
...
and
struct ContentView: View {
#ObservedObject var baz = objectivec_class.bridgingClass.baz // << this !!
var body: some View {
Button(action: {
objectivec_class.updateSwiftUi()
})
{
Text(self.baz.bar)
}
}
}
Objectivec_Class.m
#implementation Objectivec_Class
- (id)init{
if( self = [super init] ){
_stringWhichWillBeRendered = [NSMutableString stringWithString:#""];
self.bridgingClass = [BridgingClass new]; // here !!
...
I would like to answer my own question because I would also like to share how I have achieved this with the help of Asperi.
As a side subject, I had to switch back to the legacy build system because of the cyclic dependency errors I was getting from Xcode. This also implies me that there should be a better way to do all this :)
With that said and with the assumption that you did the prerequisites of bridging between Swift <-> ObjC both ways,
ContentView.swift
import Foundation
import SwiftUI
var objectivec_class = Objectivec_Class()
class Foo : ObservableObject {
#Published var bar = ""
}
#objc
class BridgingClass: NSObject {
#ObservedObject var sharedObj = Foo()
#objc func updateString(_ content: NSMutableString) {
print("This function is called from Objective C (update String)")
sharedObj.bar += content as String
}
}
struct ContentView: View {
#State var stringToBeUpdated = ""
var body: some View {
Button(action: {
objectivec_class!.updateSwiftUi()
self.stringToBeUpdated = objectivec_class!.bridgingClass.sharedObj.bar
})
{
Text(self.stringToBeUpdated.isEmpty ? "tap me" : self.stringToBeUpdated)
}
.background(Color.green)
.frame(height: 100)
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
Objective C Bridging Header,
Project-Bridging-Header.h
#import "Objectivec_Class.h"
Objectivec_Class.h
#ifndef Objectivec_Class_h
#define Objectivec_Class_h
#import <Foundation/Foundation.h>
// #import "Project-Swift.h"
/** Forward declaring the class and not including the "Project-Swift.h" file
in this header is important if you are using Xcode's legacy build system */
#class BridgingClass;
#interface Objectivec_Class : NSObject
#property (strong, nonatomic) NSMutableString* stringWhichWillBeRendered;
#property BridgingClass *bridgingClass;
- (id) init;
- (void) updateSwiftUi;
#end
#endif /* Objectivec_Class_h */
Objectivec_Class.m
#import <Foundation/Foundation.h>
#import "Project-Swift.h"
#import "Objectivec_Class.h"
#implementation Objectivec_Class
- (id)init{
if( self = [super init] ){
_stringWhichWillBeRendered = [NSMutableString stringWithString:#""];
self.bridgingClass = [BridgingClass new];
}
return self;
}
- (void) updateSwiftUi {
// Probably you did something there to update the string.
NSString *thisWillBeRendered = #"New information appended to string";
[_stringWhichWillBeRendered appendString:thisWillBeRendered];
[[self bridgingClass] updateString:_stringWhichWillBeRendered];
}
#end
Any comments are welcome, newbie here ;)
You can make use of Key-Value Observing (KVO), and have your observable object register as observer for the property you want to monitor:
class Foo : ObservableObject {
// bind the text to this
#Published var bar = ""
// no-one needs to know we delegate the work
private let worker = Objectivec_Class()
init() {
worker.observe(\.stringWhichWillBeRendered, options: [.new]) { [weak self] obj, change in
// the forced unwrap is safe here, due to the `options` parameter
self?.bar = change.newValue!
}
}
// call this from the button action
func update() {
worker.updateSwiftUi()
}
}
KVO will make sure the observation handler will be called every time the monitored property changes. And in turn, the handler will keep the published value in sync with the Objective-C one, which means you can bind your UI elements to bar instead of knowing/caring about the internals of the (View)Model.
No need for an extra bridging (boilerplate) class, no need to change the Objective-C class just to accommodate the SwiftUI design.
You can apply this technique even to classes that you don't have control over, and thus cannot bed changed, e.g. ones from 3rd party libraries (just make sure the properties you want to monitor are KVO-compliant).

How can I view the contents of an objective C Protocol?

If I have access to an objective-C Protocol and trying to figure out how to look inside it to see what methods it contains, including their signatures, etc.
I've tried NSLog and looking in the object in the debugger, as well as on the internet, and cannot find any way to do this.
I checked out the methods in objc/runtime.h after seeing the answers to this SO post: List selectors for Objective-C object and found a way to NSLog a protocol's method signatures
#import <objc/runtime.h>
Protocol *protocol = #protocol(UITableViewDelegate);
BOOL showRequiredMethods = NO;
BOOL showInstanceMethods = YES;
unsigned int methodCount = 0;
struct objc_method_description *methods = protocol_copyMethodDescriptionList(protocol, showrequiredMethods, showInstanceMethods, &methodCount);
NSLog(#"%d required instance methods found:", methodCount);
for (int i = 0; i < methodCount; i++)
{
struct objc_method_description methodDescription = methods[i];
NSLog(#"Method #%d: %#", i, NSStringFromSelector(methodDescription.name));
}
free(methods)
The only catch is that in protocol_copyMethodDescriptionList you need to specify whether you want required vs. non-required methods and whether you want class vs. instance methods. So to cover all four cases, you would need to call protocol_copyMethodDescriptionList four times and print the results for each list.

Passing struct from ObjC to Swift

Trying to use a struct from ObjC to Swift doesn't seem to be that easy. I end up getting a Unsafe pointer that I don't know if I can cast reliably.
Here is the code:
//
// In OBJC land
//
// Type declared as a struct
typedef struct node {
int children_count;
} node_t;
// Super class has a property
#property (nonatomic, assign, readonly) node_t *node;
//
// In SWIFT land
//
// Derived class tries to set the property inside the C struct
let n: UnsafeMutablePointer<node_t> = super.node // As swift compiler sees it
n.children_count = 0 // ERR!!!
Do I really need to apply unsafeBitcast here or is there a simpler/safer and more elegant way to convert what seems to be a frequent scenario?
UPDATE:
I tried using memory to access the elements of the struct and I am getting a EXC_BAD_INSTRUCTION
var node: node_t = self.node.memory
node.children_count = 42
UPDATE CONT'D & FINALE
I got it to work. Thanks to #matt's patience for making sure I groked 'memory' access completely. The other trick is to realize the assignment in one continuous statement like this:
var node: UnsafeMutablePointer<node_t> = self.node
node.memory.children_count = 42
If I do the following, the change doesn't get committed passed the function call:
var node: node_t = self.node.memory
node.children_count = 42
One problem is that this is not a "frequent scenario". In fact, this is a very odd thing to do:
#property (nonatomic, assign, readonly) node_t *node;
This thing (node_t) is a C struct. So why do you want a pointer to it? Perhaps you have no choice about this, but far and away the usual thing is simply to have the struct itself as a property:
#property (readonly) node_t *node;
In that way, the property arrives as a Swift struct called node_t, and if you have a var reference to it (not a let as you've written it), you can assign into its children_count directly, as you would expect.
If you insist on having a pointer, then you will have to dereference the pointer, won't you? You are not doing that. To do so, take the pointer's memory:
n.memory.children_count = 0

Block recursion and breaking retain cycle

To better illustrate the question, consider the following simplified form of block recursion:
__block void (^next)(int) = ^(int index) {
if (index == 3) {
return;
}
int i = index;
next(++i);
};
next(0);
XCode (ARC-enabled) warns that "Capturing 'next' strongly in this block is likely to lead to a retain cycle".
Agreed.
Question 1: Would the retain cycle be successfully broken by setting the block itself to nil, in this fashion:
__block void (^next)(int) = ^(int index) {
if (index == 3) {
next = nil; // break the retain cycle
return;
}
int i = index;
next(++i);
};
next(0);
(Note: you'd still get the same warning, but perhaps it is unwarranted)
Question 2: What would be a better implementation of block recursion?
Thanks.
To accomplish the retain-cycle-free recursive block execution, you need to use two block references - one weak and one strong. So for your case, this is what the code could look like:
__block __weak void (^weak_next)(int);
void (^next)(int);
weak_next = next = ^(int index) {
if (index == 3) {
return;
}
int i = index;
weak_next(++i);
};
next(0);
Note that the block captures the weak block reference (weak_next), and the external context captures the strong reference (next) to keep the block around. Both references point to the same block.
See https://stackoverflow.com/a/19905407/1956124 for another example of this pattern, which also uses block recursion. In addition, the discussion in the comments section of the following article is relevant here as well: http://ddeville.me/2011/10/recursive-blocks-objc/
I think #newacct is correct about #Matt Wilding's solution; it does seem that nothing will have a strong ref to the next block in that case and will result in a run time exception when run (at least it did for me).
I don't know how common it is to find recursively called blocks in the wild in objc. However, in a real world implementation (if actually required) on say, a view controller, one might define the block and then set up an internal interface property with a strong reference to said block:
typedef void(^PushButtonBlock)();
#interface ViewController ()
#property (strong, nonatomic) PushButtonBlock pushButton;
#end
#implementation ViewController
...
// (in viewDidLoad or some such)
__weak ViewController *weakSelf = self;
self.pushButton = ^() {
[weakSelf.button pushIt];
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), weakSelf.pushButton);
};
self.pushButton();
...
#end
This runs fine for me and has no compiler warnings about retain cycles (and no leaks in instruments). But, I think I would probably steer clear of doing this (recursive block calls) in most cases in objc - it's smelly. But interesting in any case.

Objective C: Good way to define C array like MyStruct theArray[18][18]?

I need to use something like a C array:
MyStruct theArray[18][18];
but I cannot define it as a property:
#property (nonatomic) MyStruct theArray[18][18];
then I have to:
#implementation MyClass
{
MyStruct theArray[18][18];
}
But is this good in term of modern Objective C guideline?
Thanks
Update:
I know I can define the struct as class and use NSMutableArray to handle it, but it is more convenient to use the C array in my case, the main concern is coding guideline and memory issue, as I do not allocate or release the theArray[18][18], not sure what its life cycle is, and I'm using ARC.
Properties cannot be of array type, while public instance variables do not provide sufficient encapsulation. A more Objective C - like approach would be defining a private 2D array, and a pair of methods or a method returning a pointer to access it - something along these lines:
// For small structs you can use a pair of methods:
-(MyStruct)getElementAtIndexes:(NSUInteger)i and:(NSUInteger)j;
-(void)setElementAtIndexes:(NSUInteger)i and:(NSUInteger)j to:(MyStruct)val;
// For larger structs you should use a single method that returns a pointer
// to avoid copying too much data:
-(MyStruct*)elementAtIndexes:(NSUInteger)i and:(NSUInteger)j;
How about use pointers instead?
#property (nonatomic) MyStruct **theArray;
The answers so far are great. . . here's two more options:
1. A bit hacky
(I'm not sure if this requires Objective-C++)
You can create the array as a public property like so:
#interface MyClass
{
#public:
MyStruct theArray[18][18];
}
#end
And then access it as follows:
myClass->theArray
2. Return a Struct
While you can't return a C-style array, you can return a struct:
typedef struct
{
CGPoint textureCoordinates[kMaxHillVertices];
CGPoint borderVertices[kMaxBorderVertices];
} HillsDrawData;
#interface Hills : NSObject
{
HillsDrawData _drawData;
}
- (HillsDrawData)drawData; //This will get cleaned up when the class that owns it does.
#end

Resources