Calling function inside function in another function - ios

I'm new in iOS Programming, and I had this problem. Let's say I have these two function:
class BaseViewController: UIViewController, ErrorMessageDelegate {
var uiView = UIView();
var viewErrorMessage:ErrorMessage!
func refresh(_sender: AnyObject) {
print("testing")
}
func getErrorMessage(message:String) {
super.viewDidLoad()
Dialog.dismiss()
ErrorMessage.message = message
viewErrorMessage = Bundle.main.loadNibNamed("ErrorMessage", owner: self, options: nil)?.first as! ErrorMessage
viewErrorMessage.delegate = self
self.view.addSubview(viewErrorMessage)
func removeSubView() {
viewErrorMessage.removeFromSuperview()
}
}
}
I want to call function removeSubView inside function refresh. I had to do that because I need to override refresh function to my subclass. And I need to put the function removeSubView in getErrorMessage because I should to. Does anyone know how to do that?

Please refer below code. It will help you to resolve the issue.
Code:
class BaseViewController: UIViewController, ErrorMessageDelegate {
var uiView = UIView();
var viewErrorMessage:ErrorMessage!
func refresh(_sender: AnyObject) {
removeSubView()
}
func getErrorMessage(message:String) {
super.viewDidLoad()
Dialog.dismiss()
ErrorMessage.message = message
viewErrorMessage = Bundle.main.loadNibNamed("ErrorMessage", owner: self, options: nil)?.first as! ErrorMessage
viewErrorMessage.delegate = self
self.view.addSubview(viewErrorMessage)
}
func removeSubView() {
viewErrorMessage.removeFromSuperview()
}
}

Yes, that is possible
func a() {
c()
}
func b() {
c()
}
func c() {
print("hello world")
}

no it is not possible - but I wonder why you would do that?

Related

ios Swift Protocol Data

I don't use storyboards.
I want to send protocol data using #objc button action.
However, the sent view controller does not run the protocol function.
May I know what the reason is?
In fact, there's a lot more code.
Others work, but only protocol functions are not executed.
The didUpdataChampion function is
Data imported into a different protocol.
I have confirmed that there is no problem with this.
protocol MyProtocolData {
func protocolData(dataSent: String)
func protocolCount(dataInt: Int)
}
class PickViewController: UIViewController,ChampionManagerDelegate{
static let identifier = "PickViewController"
var count = 0
var urlArray = [URL]()
var pickDelegate : MyProtocolData?
override func viewDidLoad() {
super.viewDidLoad()
champions.riot(url: "myURL")
}
#objc func topHand(){
pickDelegate?.protocolData(dataSent: "top")
print(count)
pickDelegate?.protocoCount(dataInt: count)
let cham = ChampViewController()
cham.modalPresentationStyle = .fullScreen
present(cham, animated: true, completion: nil)
}
//Data imported to another protocol
func didUpdataChampion(_ championManager: ChampionManager, champion: [ChampionRiot]) {
print(#function)
count = champion.count
for data in champion {
let id = data.id
guard let url = URL(string: "https://ddragon.leagueoflegends.com/cdn/11.16.1/img/champion/\(id).png") else { return }
urlArray.append(url)
count = urlArray.count
}
}
func didFailWithError(error: Error) {
print(error)
}
}
class ChampViewController: UIViewController,MyProtocolData {
var pickData = ""
var arrayCount = 0
override func viewDidLoad() {
super.viewDidLoad()
}
func protocolData(dataSent: String) {
print(#function)
pickData = dataSent
print(pickData)
}
func protocoCount(dataInt: Int) {
print(#function)
arrayCount = dataInt
print(arrayCount)
}
}
i don't see full code, for instance how you call bind to topHand(), my advice is:
check that topHand - is called
check that pickDelegate isn't nil inside topHand
Create Object fo your PickViewController class and set its delegate to self.
var yourObj = PickViewController()
override func viewDidLoad() {
super.viewDidLoad()
yourObj.delegate = self
}

use popToRootViewController and pass Data

I'm applying for a junior developer position and I've got a very specific task, that already took me 3 days to complete. Sounds easy - pass data to rootViewController.
That's what I've done:
1)
private func userDefaultsToRootController() {
let input = textField.text!
defaults.set(input, forKey: "SavedLabel")
navigationController?.popViewController(animated: true)
}
private func segueToRootViewController() {
let destinationVC = MainScreen1()
let input = textField.text!
if input == "" { self.navigationController?.popToRootViewController(animated: true) }
destinationVC.input = input
navigationController?.pushViewController(destinationVC, animated: true)
}
private func popToNavigationController() {
let input = textField.text!
if let rootVC = navigationController?.viewControllers.first as? MainScreen1 {
rootVC.input = input
}
navigationController?.popToRootViewController(animated: true)
}
I've used CoreData
But here is the difficult part - I've got an email, that all these methods are not good enough and I need to use delegate and closure. I've done delegation and closures before, but when I popToRootViewController delegate method passes nil. Could you at least point where to find info about this?
** ADDED **
There are 2 View Controllers: Initial and Second one.
That's what I have in the Initial View Controller:
var secondVC = MainScreen2()
override func viewDidLoad() {
super.viewDidLoad()
secondVC.delegate = self
}
That's how I push SecondViewController
#objc private func buttonTapped(_ sender: CustomButton) {
let nextViewController = MainScreen2()
navigationController?.pushViewController(nextViewController, animated: true)
}
In SecondViewController I've got this protocol
protocol PassData {
func transferData(text: String)
}
Also a delegate:
var delegate: PassData?
This is how I go back to initial view controller
#objc private func buttonTapped(_ sender: CustomButton) {
if let input = textField.text {
print(input)
self.delegate?.transferData(text: input)
self.navigationController?.popToRootViewController(animated: true)
}
}
Back to the Initial view controller where I've implemented delegate method
extension MainScreen1: PassData {
func transferData(text: String) {
print("delegate called")
label.text = text
}
}
Delegate doesn't get called.
BASED ON YOUR EDIT:
You must set the delegate in buttonTapped
#objc private func buttonTapped(_ sender: CustomButton) {
let nextViewController = MainScreen2()
nextViewController.delegate = self // HERE WHERE YOU SET THE DELEGATE
navigationController?.pushViewController(nextViewController, animated: true)
}
You can delete the second instance and your code in viewDidLoad. That's not the instance you push.
This should point you in the right direction to use delegation and completion handler.
protocol YourDelegateName {
func passData(data:YourDataType)
}
class SecondViewController: UIViewController {
var delegate: YourDelegateName?
func passDataFromSecondViewController(){
YourCoreDataClass.shared.getCoreData { (yourStringsArray) in
self.delegate?.passData(data: yourStringsArray)
self.navigationController?.popToRootViewController(animated: true)
}
}
class InitialViewController: UIViewController, YourDelegateName {
override func viewDidLoad() {
super.viewDidLoad()
// or whenever you instantiate your SecondViewController
let secondViewController = SecondViewController()
secondViewController.delegate = self //VERY IMPORTANT, MANY MISS THIS
self.navigationController?.pushViewController(createVC, animated: true)
}
func passData(data:YourDataType){
//user your data
}
}
class YourCoreDataClass: NSObject {
static let shared = YourCoreDataClass()
func getCoreData (completion: ([String]) -> ()){
........... your code
let yourStringsArray = [String]() // let's use as example an array of strings
//when you got the data your want to pass
completion(yourStringsArray)
}
}

UINavigationController return nil Swift

When i try print(self.navigationController) in viewWillApear or viewDidLoad all ok. But when delegate return response from API print(self.navigationController) return nil. What could it be?
extension EnterpriseList: APIDataDelegate {
func successRequest() { //print(self.navigtionController) == nil
DispatchQueue.main.async {
self.navigationController?.popToRootViewController(animated: true)
}
}
func badRequest() {
DispatchQueue.main.async {
Alert.showWarningAlert(withTitle: "Внимание!", andMessage: "Ошибка получения данных, попробуйте чуть позже", whereSender: self)
}
}
}
class EnterpriseList: UIViewController {
let dataSource = DataSource()
override func viewDidLoad() {
super.viewDidLoad()
dataSource.delegate = self
dataSource.makeAPICall()
}
}
extension EnterpriseList: APIDataDelegate {
func successRequest() {
DispatchQueue.main.async {
self.navigationController!.popToRootViewController(animated: true)
}
}
func badRequest() {
DispatchQueue.main.async {
}
}
}
protocol APIDataDelegate: class {
func successRequest()
func badRequest()
}
class DataSource {
var delegate: APIDataDelegate?
private let queue = DispatchQueue(label: "Test", qos: .background, attributes: [], autoreleaseFrequency: .inherit, target: nil)
func makeAPICall() {
queue.asyncAfter(deadline: .now() + 2) {[weak self] in
self?.delegate?.successRequest()
}
queue.asyncAfter(deadline: .now() + 10) {[weak self] in
self?.delegate?.successRequest()
}
}
}
The crash is because you are calling the method on deallocated object.
Here is how to fix this:
Make your delegate is weak and you are correctly deallocating the objects
weak var delegate: APIDataDelegate?
Thx #Manoj for answers it's halped me. But i found solution in other. Besides SurveyList i have UserMenu where i create static let view controllers. Removing static i solved my problem.

Protocol Delegate between XIB and View Controller

So I have XIB View and View Controller. I want when a button in my XIB clicked (didTapTryAgain Button), the called a function from my view controller. Then I tried to create a protocol and delegate for the class. But it still won't called my function. Here's my XIB view class:
import UIKit
protocol ErrorMessageDelegate {
func refresh(_sender: AnyObject)
}
class ErrorMessage: UIView {
#IBOutlet weak var imageViewError: UIImageView!
#IBOutlet weak var labelError: UILabel!
#IBOutlet weak var buttonTryAgain: UIButton!
static weak var shared: ErrorMessage?
var delegate: ErrorMessageDelegate?
static var message: String?
override func awakeFromNib() {
ErrorMessage.shared = self
labelError.text = ErrorMessage.message
}
#IBAction func didTapTryAgain(_ sender: UIButton) {
delegate?.refresh(_sender: buttonTryAgain)
}
}
And here's my View Controller class:
import Foundation
class BaseViewController: UIViewController, ErrorMessageDelegate {
func refresh(_sender: AnyObject) {
print("I hope my function work here")
}
var uiView = UIView();
override func viewDidLoad() {
super.viewDidLoad()
ErrorMessage.shared?.delegate = self
}
func getErrorMessage(message:String) {
super.viewDidLoad()
Dialog.dismiss()
ErrorMessage.message = message
guard let viewErrorMessage = Bundle.main.loadNibNamed("ErrorMessage", owner: self, options: nil)?.first as? ErrorMessage else { return}
self.view.addSubview(viewErrorMessage)
}
}
I'm following this answer for my code, and it still not working. Is anyone know how to do it? Thank you!
Your problem is that you set the delegate for a shared instance here
ErrorMessage.shared?.delegate = self / here shared?. is nil
but here
guard let viewErrorMessage = Bundle.main.loadNibNamed("ErrorMessage", owner: self, options: nil)?.first as? ErrorMessage else { return}
self.view.addSubview(viewErrorMessage)
you create a separate instance and add it
You need
var viewErrorMessage:ErrorMessage! // add to the vc
viewErrorMessage = Bundle.main.loadNibNamed("ErrorMessage", owner: self, options: nil)?.first as! ErrorMessage
viewErrorMessage.delegate = self
self.view.addSubview(viewErrorMessage)
Also completely git rid of
static weak var shared: ErrorMessage?
Simply use this code then your delegate method will be call.
func getErrorMessage(message:String) {
ErrorMessage.message = message
guard let viewErrorMessage = Bundle.main.loadNibNamed("ErrorMessage", owner: self, options: nil)?.first as? ErrorMessage else { return}
viewErrorMessage.delegate = self
self.view.addSubview(viewErrorMessage)
}
and call method where ever you want to open the popup
getErrorMessage(message: "Test Message")

Sinch video doen't want to work on iOS (Swift)

So basically I want to enable Sinch Video in iOS application.
For testing purposes I've created SinchManaevger which is singleton and I instatiate it in AppDelegate:
class SinchManager: NSObject, SINClientDelegate, SINCallClientDelegate {
static let sharedInstance = SinchManager()
var client: SINClient?
func initSinchClientWithUserId(id: String) {
if client == nil {
if case .Authenticated(let currentUser, _) = SessionManager.sharedInstance.state.value {
self.client = Sinch.clientWithApplicationKey("xyz", applicationSecret: "xyz", environmentHost: "sandbox.sinch.com", userId: currentUser.username)
print("sinchClient")
print(client!)
self.client!.delegate = self
self.client!.setSupportCalling(true)
self.client!.enableManagedPushNotifications()
self.client!.start()
self.client!.startListeningOnActiveConnection()
}
}
}
func clientDidStart(client: SINClient!) {
print("clientDidStart")
self.client!.callClient().delegate = self
}
func clientDidStop(client: SINClient!) {
print("clientDidStop")
}
func clientDidFail(client: SINClient!, error: NSError!) {
print("clientDidFail")
}
func client(client: SINCallClient!, didReceiveIncomingCall call: SINCall!) {
print("didReceiveIncomingCall")
let sinchVC = SinchVC(username: currentUser.username)
let sinchNC = DNMMainNC(rootViewController: sinchVC)
sinchVC.call = call
}
}
And I've created Sinch ViewController which is initialized with username which will be called:
class SinchVC: UIViewController, SINCallDelegate {
private let videoController = SinchManager.sharedInstance.client!.videoController()
private let audioController = SinchManager.sharedInstance.client!.audioController()
private let callClient: SINCallClient
private var call: SINCall!
let username: String
private var mainView: SinchView { return view as! SinchView }
override func loadView() {
view = SinchView()
}
init(username: String) {
self.username = username
self.callClient = SinchManager.sharedInstance.client!.callClient()
super.init(nibName: nil, bundle: nil)
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override func viewDidLoad() {
super.viewDidLoad()
call.delegate = self
self.mainView.videoView.addSubview(self.videoController.localView())
self.videoController.localView().contentMode = .ScaleToFill
if self.call.direction == SINCallDirection.Incoming {
self.audioController.startPlayingSoundFile(self.pathForSound("incoming.wav") as String, loop: true)
}
if self.call.details.videoOffered {
print("video offered")
self.mainView.videoView.addSubview(self.videoController.localView())
self.videoController.localView().contentMode = .ScaleToFill
}
mainView.videoView.addSubview(self.videoController.localView())
mainView.answerButton.addTarget(self, action: #selector(answer), forControlEvents: .TouchUpInside)
mainView.declineButton.addTarget(self, action: #selector(decline), forControlEvents: .TouchUpInside)
}
override func viewWillAppear(animated: Bool) {
super.viewWillAppear(animated)
self.audioController.enableSpeaker()
}
func pathForSound(string: String) -> NSString {
let nsSt = NSBundle.mainBundle().resourcePath! as NSString
return nsSt.stringByAppendingPathComponent(string)
}
func answer() {
call.answer()
}
func decline() {
call.hangup()
}
func callDidEstablish(call: SINCall!) {
print("callDidEstablish")
}
func callDidEnd(call: SINCall!) {
print("callDidEnd")
}
func callDidProgress(call: SINCall!) {
print("callDidProgress")
self.audioController.startPlayingSoundFile(self.pathForSound("ringback.wav") as String, loop: true)
}
func callDidAddVideoTrack(call: SINCall!) {
print("callDidAddVideoTrack")
mainView.videoView.addSubview(self.videoController.remoteView())
}
}
Problem is when I try to call from my app to other phone with my app nothing happens (didReceiveIncomingCall delegate method doesn't get called at all)
If I try to call from my app to SinchVideo sample app then video call gets initiated normal. But when i call from SinchVideo app to my app nothing happens in my app. So probably i've forgot to add some notification or something to tell my app when the call is incoming. If you could help I would be very grateful. Thanks
EDIT: I managed to make didReceiveIncomingCall work but now call.answer isnt working. (nothing happens when call.answer is called and i see that my phone is ringing)
I am not sure what DNMMainNC does in your did recieve incoming call,
let sinchNC = DNMMainNC(rootViewController: sinchVC) What does DNMMainNC do?
sinchVC.call = call // private var?
But its looks kind of weird to set a private var call from your code, should that not be public or have a constructor like your init but with a call

Resources