Sinch didReceiveIncomingCall Never Called - ios

I want to be able to make calls App-To-App using Sinch. I have followed the steps and converted the code into Swift. For some reason the method didReceiveIncomingCall is never called. I will paste some of my code so you can see how I initiated the SinchClient
in my viewDidLoad method I have.
sinchClient = Sinch.clientWithApplicationKey("key", applicationSecret: "secret", environmentHost: "sandbox.sinch.com", userId: "idOfUser")
sinchClient.setSupportCalling(true)
sinchClient.delegate = self
sinchClient.start()
sinchClient.startListeningOnActiveConnection()
Then I make a call from user1 to user2 using the following.
if(clientStarted){
let callClient = sinchClient.callClient()
callClient.callUserWithId("user2")
sinchCall.delegate = self
}
This is my delegate methods for the SINCallClientDelegate
extension CallViewController: SINCallClientDelegate{
func client(client: SINCallClient!, didReceiveIncomingCall call: SINCall!) {
print("GOT ME AN INCOMING CALL")
sinchCall = call
sinchCall.delegate = self
sinchCall.answer()
}
}
For some reason, the method didRecieveIncomingCall never gets called. Sometimes I also get the following error:
WARNING: Delegate for SINCallClient not assigned? Delegate should handle incoming call. (see -[SIN allClient Delegate notifyDelegate fIncomingCall:])
I think maybe it might have something to do with sinchClient.startListeningOnActiveConnection() but I am not sure.
couple things to note is that I do know when my sinchClient is started because I listen for it in my delegate. When clientDidStart is called, I change the variable for clientStarted: Bool. I also have three delegates in one file (SINCallClientDelegate, SINCallDelegate, and SINClientDelegate). It waits for sinchClient to be started before making any calls.

So my solution was so simple. I never set the sinchClient.callClient().delegate = self. Please read the comments on the question.
sinchClient.callClient().delegate = self
sinchClient.setSupportCalling(true)
sinchClient.delegate = self
sinchClient.start()
sinchClient.startListeningOnActiveConnection()

Related

Objective C: Unable to execute callback method in viewDidLoad function

I am new to iOS objective C and currently am enhancing some features to an existing project. I would like to implement a callback method to return the results from an API call in the viewDidLoad method as I need the results to determine the number of icons to display on the screen.
I have looked around for various answers, however, I am not sure what has went wrong and I am unable to return the responses from the APIs to the NSMutableArray in the ViewDidLoad method. I would greatly appreciate any help on how to go about get the response into the customerArray in the viewDidLoad method
This is the Service Delegate header file that defines the method:
I made use of the first method requestCompleted in my ViewController file to retrieve the response returned from the API. Within this method, customerArray which is a globally declared array contains the items that was returned from the API, however when this array was called in the viewDidLoad method, it appears to be null.
I tried the following way to retrieve using the dispatch async method, but the customer Array is still empty
You are printing customerArray, before dispatch_async executed. Try putting breakpoint in requestCompleted method or put print statement in requestCompleted method. and check the value.
You can't execute the callback method in viewDidLoad function. And then this attempt is not good pattern in iOS.
I understand what you want. You want to display various icons when view controller is appeared.
For this, you may need to use UITableView or CollectionView.
In this case, i have been doing following.
First, Run API call by using Alamofire
Second. Show loading icon (by using HUD)
Third, In API callback, fetch the list information and reload tableview.
*Following is swift code but it is very similar with Objective C.
override func viewDidLoad() {
super.viewDidLoad()
HUD.show(.rotatingImage(UIImage(named: "rotateLogo")), onView: nil)
APIManager.request(Constant.sdkCredential,
parameters: [:],
fullResponse:true)
{ (response, success, error) in
if success == true {
guard (response as? Dictionary<String,Any>) != nil else {
self.showAlert(withTitle: "Error", message: "Invalid Credential")
return
}
if let dict = response as? Dictionary<String,Any> {
print(dict)
if let dictData = dict["data"] as? Dictionary<String,Any>{
self.tableView.reloadData();
}
}
} else {
HUD.hide()
self.showAlertWithError(error)
}
}
}

Why this callback doesn't gets called unless I assign the result of this function to a class variable

I have this function that is from the AppAuth examples, I realised that in iOS13 I don't really need to store the return value for the OIDAuthState.authState, so I tried to clean up the code by removing the appDelegate.currentAuthorizationFlow =, but once I remove that, the callback doesn't gets called anymore. And this currentAuthorizationFlow is not used anywhere else in the code.
I have also tried assigning the result of OIDAuthState.authState to a function local variable, where the call back also will not be called.
If I assign the results of OIDAuthState.authState to a class member variable in the current class, then the call back will be called.
Why is the behaviour as such? It seems very baffling to me.
func signInGmail() {
let redirectURI = URL(string: gmail_kRedirectURI)!
let appDelegate = UIApplication.shared.delegate as! AppDelegate
let config = GTMAppAuthFetcherAuthorization.configurationForGoogle()
let scopes = [OIDScopeOpenID, OIDScopeProfile, OIDScopeEmail, kGTLRAuthScopeGmailReadonly]
let request = OIDAuthorizationRequest.init(configuration: config, clientId: gmail_kClientID, scopes: scopes, redirectURL: redirectURI, responseType: OIDResponseTypeCode, additionalParameters: nil)
appDelegate.currentAuthorizationFlow = OIDAuthState.authState(byPresenting: request, presenting: self, callback: { (authState, error) in
//handleError
if let authState = authState {
let authorizer = GTMAppAuthFetcherAuthorization(authState: authState)
self.pickGmailLabels(authorizer: authorizer)
}
})
}
Here's what the documentation says about the return value of authState(byPresenting:presenting:callback:)
Returns
A OIDExternalUserAgentSession instance which will terminate when it receives a cancel (OIDExternalUserAgentSession-p) message, or after processing a resumeExternalUserAgentFlowWithURL: (OIDExternalUserAgentSession-p) message.
What might happen here is that either the dealloc for the returned session calls cancel, or the session along with the callback get deallocated if no one retains them. And since you no longer store a reference to it when you remove the assignment, the session might get discarded right away.
However the need to retain the session is not explicitly stated into the documentation, so if this is the root cause of the problem, either the documentation is laking this piece of information, or there's a bug in the implementation.
Note that it's not an unusual pattern having to hold on some async task identifier to make sure the whole operation completes, however this should be stated into the documentation, if this is the intended behaviour.
The function returns an object, and you need to keep that object alive. That is done by assigning it to a strong variable. If you don't do that, then the object will be released at the next opportunity.

How to act on an async delegate function in swift

I'm currently implementing against an internal SDK with delegation in swift.
The current process for performing an action
1.) Initiate 'start' which will call the delegate
2.) My implemented delegate method will make an API call for a token
3.) The token is then used to make subsequent requests within my action.
The issue that I have is that I can't pass a closure/callback into the start process which is obviously async but then how do i await the completion of the delegate method all within the same function?
I'm thinking notifications might be the answer but I'm not a swift ninja.
So... (pseudocode)
func performAction() {
internalSDK.start()
// calls my implemented delegate
// sets the token on self
doActionUsingTheTokenRetrievedInMyDelegateMethod(token: self.token)
}
It feels like I need some kind of await or an observer which is then removed at the end of the call.
It should also be noted that the delegate method is generic so I can't implement the code within the method itself.
I would try to make do with the simplest possible tools available, e.g. a property observer on the token, like so:
class Foo {
var token: Token {
didSet {
doActionUsingTheTokenRetrievedInMyDelegateMethod(token: self.token)
}
}
func performAction() {
internalSDK.start()
// calls my implemented delegate
// sets the token on self
}
}

Are delegates necessary here?

This might be very basic. But, I am not very sure if the delegates are necessary in the following scenario?
Are delegates used in synchronous ways? If yes, is it good to call a delegate method in a function called by a caller who is a delegate[Like the example below]?
class FooViewController: UIViewController {
func login() {
let loginHelper = LoginHelper()
loginHelper.fooDelegate = self
loginHelper.shouldEnableLogin()
}
func enableLogin() {
// Do some UI updates
}
func reset() {
// Clear some values in the views
}
}
class LoginHelper {
weak var delegate: fooDelegate?
func shouldEnableLogin() {
//clear some text views
delegate.reset()
//do some validation, synchronous
delegate.enableLogin()
}
}
Delegates are a design pattern that allows one object to send messages to another object when a specific event happens. Imagine an object A calls an object B to perform an action. Once the action is complete, object A should know that B has completed the task and take necessary action, this can be achieved with the help of delegates!
I think the crux here is your question "Are delegates used in synchronous ways?".
The fundamental delegate mechanism is synchronous: I.e. the called delegate method will be on the same thread as the caller. So if the caller is your object then you control what thread this occurs on.
However the caller could create a new thread and then call the delegate method from that. So if the caller is not yours, check the documentation for it carefully before relying on the call being on the same thread.

How do you set the delegate for an SFSpeechRecognitionTask?

In most cases, setting a delegate is as simple as implementing the delegate protocol in a class and declaring an instance of that class as the delegate for an instance of whatever you're using.
I actually used this same basic concept for the SFSpeechRecognizer which belongs to the same speech framework in my code. (Pseudocode example):
class myViewControllerClass: SFSpeechRecognizerDelegate{
let mySpeechRecognizer = SFSpeechRecognizer(...)
viewDidLoad(){
mySpeechRecognizer.delegate = self
}
...
//SFSpeechRecognizerDelegate Functions here
...
}
//This works as expected, woo!
However, it seems that SFSpeechRecognitionTask has no delegate property which can be set. I tried implementing the 'SFSpeechRecognitionTaskDelegate' protocol in my class in hopes that it would just magically work. However the delegate functions don't seem to ever be called. Which kind of makes sense, because it has no way of knowing that my view controller should be the delegate so why would it!?
The apple documentation covers the protocol itself and how to use it:
https://developer.apple.com/reference/speech/sfspeechrecognitiontaskdelegate
But the documentation for the task itself doesn't identify any delegate property:
https://developer.apple.com/reference/speech/sfspeechrecognitiontask
Also for reference here's the SFSpeechRecognizer documentation which has the protocol AND identifies a delegate property as you'd expect:
https://developer.apple.com/reference/speech/sfspeechrecognizer
Is there some alternative way I'm supposed to be setting the delegate for an SFSpeechRecognitionTask? Or is it handled in some completely different way?
In SFSpeechRecognizer there is a method
func recognitionTask(with request: SFSpeechRecognitionRequest,
delegate: SFSpeechRecognitionTaskDelegate) -> SFSpeechRecognizerTask
Where you can pass on the delegate for the SFSpeechRecognizerTask.
I did it like this in ViewController:
recognitionTask = speechRecognizer?.recognitionTask(with: speechRecognitionRequest, delegate: self)

Resources