Bind Method With Delegate - objective-c

I'm creating a binding library to bind native Objective-C framework.
I have the following delegate which I need to add it's declaration to ApiDefinition file and then I need to implement it using my Xamarin.iOS app:
- (void)Initialize:(id <MMSDKDelegate> _Nullable)pDelegate;
MMSDKDelegate:
#protocol MMSDKDelegate <IMMDelegate>
- (void)Started;
#end
IMMDelegate:
#protocol IMMDelegate
- (void)Inserted;
- (void)Removed;
- (void)ReaderConnected;
- (void)ReaderRemoved;
#end
I need the required definition in ApiDefinition file and I need a sample code to call this method from my Xamarin.iOS app.
Update
The Framework I'm dealing with is communicating with card reader device attached with iPhone to read ID card info, it has methods to be called on reader inserted / removed & card inserted / removed..
I have implemented the answer by #cole-xia, but the issue is the methods inside IMMDelegate are never called when I insert card reader or ID. When I call ReadCardData(), it should call Started() which will display information saved by Inserted(), but the current result is that Started() method is called after calling ReadCardData(), but Inserted() and ReaderConnected() are never called in any stage.
In the demo app of Framework, it is used as the following (and works properly):
// Demo app -> ViewController.m
#interface ViewController () <MMSDKDelegate>
#end
#implementation ViewController {
MMSDK *sdkInstance;
}
- (void)viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];
sdkInstance = [MMSDK SharedInstance];
[sdkInstance Initialize:self];
}
- (void)Started
{
// Update UI by: reading in progress ..
}
- (void)Inserted
{
// Update UI by: card inserted
// And read card data
[self readData:self];
}
- (void)Removed
{
// Update UI by: card removed
}
- (void)ReaderConnected
{
// Update UI by: card reader connected
}
- (void)ReaderRemoved
{
// Update UI by: card reader removed
}
- (IBAction)readData:(id)sender
{
var *data = [sdkInstance ReadCardData:YES pWithSignatureImage:YES pWithAddressData:YES];
if (data.hasError) {
// No data fetched
return;
}
if (data) {
// return card data
}
}
All suggestions are welcome and appreciated.
In summary, I just need to do same functionality of demo app in Xamarin.iOS app.

Use Sharpie to create ApiDefinition
The result on my side :
// #protocol IMMDelegate
[BaseType (typeof (NSObject))]
[Protocol, Model]
interface IMMDelegate
{
// #required -(void)Inserted;
[Abstract]
[Export ("Inserted")]
void Inserted ();
// #required -(void)Removed;
[Abstract]
[Export ("Removed")]
void Removed ();
}
// #protocol MMSDKDelegate <IMMDelegate>
[BaseType (typeof (NSObject))]
[Protocol, Model]
interface MMSDKDelegate : IMMDelegate
{
// #required -(void)Started;
[Abstract]
[Export ("Started")]
void Started ();
}
// #interface ACR : NSObject
[BaseType (typeof(NSObject))]
interface YourClass
{
// -(void)Initialize:(id<MMSDKDelegate> _Nullable)pDelegate;
[Export ("Initialize:")]
void Initialize ([NullAllowed] MMSDKDelegate pDelegate);
}
Usage:
class MyDelegate : MMSDKDelegate {
public void Started()
{
}
public override void Removed()
{
}
public override void Inserted()
{
}
}
//In ViewController
public override void ViewDidLoad()
{
base.ViewDidLoad();
YourClass yourClass = new YourClass();
yourClass.Initialize(new MyDelegate());
}

Along with Cola Xia's answer you may also need to make sure that, such third party device SDK integration requires some entries in the info.plist file's "Supported external accessory protocols" key.
Please check XCode sample and check if there is an entry for the "Supported external accessory protocols" key. If it is there, then you should add them in your Xamarin.iOS project's info.plist file.
I hope this may help!

Related

How to display Drop Down in xamarin form. IOS

This Is My IOS IPad Page I want to display dropdown as show in image ,Pleases help me how can I write a code ,
I have use picker for that but the menu item is display on bottom ,How i resolve this issue
Here is a workaround that achieve such "Drop Down" via "control combination".
First, add a UITextField on the view to show the item selected.
UITextField _dropTextField;
UIView _dropDownView;
UIPickerView _pickerView;
public override void ViewDidLoad()
{
base.ViewDidLoad();
// Perform any additional setup after loading the view, typically from a nib.
this.View.BackgroundColor = UIColor.White;
// add textfield
_dropTextField = new UITextField();
_dropTextField.Frame = new CGRect(100, 100, 300, 30);
_dropTextField.BackgroundColor = UIColor.Gray;
this.View.AddSubview(_dropTextField);
// call CreateDropDownView
CreateDropDownView();
}
Second, define a method that create a custom UIView holds a UIPickerView.
// create a custom UIView to show pickView
private void CreateDropDownView()
{
_dropDownView = new UIView(new CGRect(_dropTextField.Frame.X, _dropTextField.Frame.Y,
_dropTextField.Frame.Width, 300));
_dropTextField.Delegate = this;
_pickerView = new UIPickerView();
_pickerView.Frame = new CGRect(_dropTextField.Bounds.X, _dropTextField.Bounds.Y + _dropTextField.Frame.Height, _dropTextField.Frame.Width, 300);
PeopleModel pickerModel = new PeopleModel(_dropTextField, _dropDownView);
_pickerView.Model = pickerModel;
_dropDownView.AddSubview(_pickerView);
}
Then, to show the UIView when TextField focused, you also need to implement interface IUITextFieldDelegate.
// show pickerview
[Export("textFieldShouldBeginEditing:")]
public bool ShouldBeginEditing(UITextField textField)
{
View.AddSubview(_dropDownView);
UIApplication.SharedApplication.KeyWindow.BringSubviewToFront(_pickerView);
return false;
}
As for the PeopleModel in the above code, please refer to "class PeopleModel" in this documentation. Also, you need to override some method in it.
private UITextField dropTextField;
private UIView dropDownView;
public PeopleModel(UITextField dropTextField, UIView dropDownView)
{
this.dropDownView = dropDownView;
this.dropTextField = dropTextField;
}
public override nint GetComponentCount(UIPickerView pickerView)
{
return 1;
}
// ...
public override void Selected(UIPickerView pickerView, nint row, nint component)
{
dropDownView.RemoveFromSuperview();
dropTextField.Text = $"{names[pickerView.SelectedRowInComponent(0)]}";
}
// ...

Using a function in NSSetUncaughtExceptionHandler

I want to reference some state in a NSSetUncaughtExceptionHandler, and so don't want to pass in a function but a method instead. But how?? The state I need to reference is a callback from a react native app. So far i have:
#import "RNUncaughtExceptionReporter.h"
#implementation RNUncaughtExceptionReporter
- (dispatch_queue_t)methodQueue
{
return dispatch_get_main_queue();
}
RCT_EXPORT_MODULE()
RCT_EXPORT_METHOD(listen:(RCTResponseSenderBlock)listener)
{
callback = listener;
NSSetUncaughtExceptionHandler(/* what goes here? */);
}
- (void) unhandledExceptionHandler(NSException *exception) {
callback(#[#"something went wrong..."]);// todo: send the detail of the exception
}
#end
try this !
NSSetUncaughtExceptionHandler (&UncaughtExceptionHandler);
void UncaughtExceptionHandler(NSException* exception)
{
/* do anything u want with the exception */
}

Fails to write proper syntax for block that uses typedef

I have Objective-C code that I try to convert to Swift but failed.
typedef void (^ CDVAddressBookWorkerBlock)(
ABAddressBookRef addressBook,
CDVAddressBookAccessError* error
);
#interface CDVAddressBookHelper : NSObject
{}
- (void)createAddressBook:(CDVAddressBookWorkerBlock)workerBlock;
#end
And this is Objective-C implementation:
CDVAddressBookHelper* abHelper = [[CDVAddressBookHelper alloc] init];
[abHelper createAddressBook:
^(ABAddressBookRef addrBook, CDVAddressBookAccessError* errorCode)
{
/* ...*/
}
];
How to write it in Swift?
From documentation:
{(parameters) -> (return type) in expression statements}
This is a template xCode offers:
This is what I tried:
var abHelper:CDVAddressBookHelper = CDVAddressBookHelper()
abHelper.createAddressBook(
{(addrBook:ABAddressBookRef, errCode:CDVAddressBookAccessError) in
if addrBook == nil {
}
} )
Error:
Type 'ABAddressBook!' does not conform to protocol 'AnyObject'`
[EDIT]
Regards to: swift-closure-declaration-as-like-block-declaration post I tried to write typealias:
typealias CDVAddressBookWorkerBlock = (addrBook:ABAddressBookRef, errCode:CDVAddressBookAccessError) -> ()
What next?
How to make it work?
Thanks,
Check out the docs about how to work with Cocoa and Core Foundation.
This should work:
abHelper.createAddressBook() {
(addrBook:ABAddressBook?, errCode:CDVAddressBookAccessError!) in
if addrBook == nil {
}
}

Release block or cancel block objc

Am using a Class to make all the network calls to fetch data.
// Helper Class method for network calls
- (void) dataForUser:user withCompletionHandler:(void(^)(id response)) onComplete {
[[webClient sharedObject] fetchDataForUser:user withCompletionHandler:(void(^)(id response)) onComplete {
// do something to get data
onComplete(data);
}];
}
// View Controller's Model Class
- (void) getDataWithCompletionHandler:(void(^)(id)) onComplete {
// helperClassObj is a class variable
[helperClassObj dataForUser:userInfo withCompletionHandler:^(id response) {
// process response and store it as response 1.
onComplete(response1);
}];
}
I cannot make another request until one gets completed. How can I cancel a previous request so that I dont have to wait until I get data. Like I requested data for user1 and request for data for user2 and I need to display user2 data and be able to cancel the previous call.
// Helper Class method for network calls
- (void) dataForUser:user withCompletionHandler:(void(^)(id response)) onComplete {
[webClient fetchDataForUser:user withCompletionHandler:^(id response) {
// do something to get data
if(onComplete) {
onComplete(data);
}
}];
}
// View Controller's Model Class
BOOL isLastRequestCancelled = NO;
- (void) getDataWithCompletionHandler:(void(^)(id)) onComplete {
isLastRequestCancelled = YES;
// helperClassObj is a class variable
[helperClassObj dataForUser:userInfo withCompletionHandler:^(id response) {
// process response and store it as response1
if(!isLastRequestCancelled) {
if(onComplete) {
onComplete(response1);
}
}
isLastRequestCancelled = NO;
}];
}

Obj-C function declaration needs semi-colon?

This is really simple but driving me nuts.
I am trying to implement a simple function in my Objective-C code. When I write this,
NSInteger Sort_Function(id id1, id id2, void *context) {
}
I get an error that a semi-colon was expected at the end of the declaration. However, I've seen this type of syntax in many, many examples. What could I possibly be doing wrong? If it matters, this is an iOS app and the function is nested in an if clause. Thanks in advance.
The function definition -- this snippet you posted -- is "nested in a if clause"? That's unfortunately illegal in C (and Obj-C by extension) -- all function declarations and definitions have to be at the top level of the file. Inside an #implementation section is also an option:
// Start of file
// Declaration or definition valid here
void my_func(void); // Declaration
void my_other_func(void);
void my_third_func(void);
void my_func(void) { // Definition
return;
}
#implementation MyClass
// Definition also valid here
void my_other_func(void) {
return;
}
- (void) myMethod {
if( YES ){
void my_third_func(void) { // Invalid here
return;
}
}
}
#end
Is it possible you're confusing the function syntax with block syntax?
// The caret indicates definition of a block, sort of an anonymous function
int (^myBlock)(int);
myBlock = ^int (int my_int) {
return my_int;
};