triggering segue after an ibaction - ios

I'm trying to perform a segue after my IBAction has already happend.
This is my code and as you can see when I press the button I make a get request with alamofire. The problem is that the request is (as I understand) an async method so the segue will unwind and perform eve if the getPlayer method hasn't done what it's supposed to. The only way I could fix it is by putting the perfomrsegue method inside an if statement where I check for the value of person.name, but I have to press the button twice and I just can't figure out how to solve this!
#IBAction func getPlayerPressed(_ sender: UIButton) {
userDefaults.set(tagTextField.text!, forKey: "userTag")
let userTag = userDefaults.string(forKey: "userTag")
getPlayerData(with: userTag!)
performSegue(withIdentifier: "goToPlayerProfile", sender: self)
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
let destionationVC = segue.destination as! PlayerProfileViewController
destionationVC.playerName = player.name
print(destionationVC.playerName)
print("prepared for segue")
}
func getPlayerData (with tag: String) {
let finalURL = baseURL + tag
Alamofire.request(finalURL, headers: headers).responseJSON { (response) in
if response.result.isSuccess {
print("Got player data!")
let playerJSON = JSON(response.result.value!)
self.player.name = playerJSON["name"].stringValue
print(self.player.name)
} else {
print("Error: \(response.result.error!)")
}
}

Perform segue after async alamofire request is completed.
func getPlayerData (with tag: String) {
let finalURL = baseURL + tag
Alamofire.request(finalURL, headers: headers).responseJSON { (response) in
if response.result.isSuccess {
print("Got player data!")
let playerJSON = JSON(response.result.value!)
self.player.name = playerJSON["name"].stringValue
print(self.player.name)
DispatchQueue.main.async {
self.performSegue(withIdentifier: "goToPlayerProfile", sender: self)
}
} else {
print("Error: \(response.result.error!)")
}
}
}

Related

How to pass data in a closure to another scene

It is my first app in swift. I am using Alamofire for my HTTP request. Coming from Android, I know it is possible to attach serialized object to navcontroller action while navigating from one screen to another.
I want to be able to perform segue after from the viewmodel subscription and attach the resultant token to the segue as I will be using it for verification at the next screen.
I have tried didSet but to no avail.
How can I do this in swift.
//MARK: Register user
#IBAction func registerUser(_ sender: Any) {
let fullName = firstNameTF.text! + " " + lastNameTF.text!
let email = emailTF.text
let password = passwordTF.text
let phone = phoneNumberTF.text
let country = countryDropDown.text
let user = User(name: fullName, email: email, password: password, country: country, phone: phone, token: nil)
var tk = ""{
didSet{
token = tk
}
}
authViewModel.registerUser(user: user).subscribe(onNext: { (AuthResponse) in
print("messaage \(String(describing: AuthResponse.message))")
self.tokens = AuthResponse.token
self.performSegue(withIdentifier: "gotoVerification", sender: self)
}, onError: { (Error) in
print("Error: \(Error.localizedDescription)")
}, onCompleted: nil) {
}.disposed(by: disposeBag)
print("token \(token)")
// AF.request(url, method: .post, parameters: user, encoder: JSONParameterEncoder.default).responseDecodable(of:AuthResponse.self){response in
//
// response.map { (AuthResponse) in
// print("messaage \(String(describing: AuthResponse.message))")
// }
//
// print("user: \(user)")
// print("response \(String(describing: response))")
// }
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if let vc = segue.destination as? UserVerification{
//
vc.tokens = token
print("token \(token)")
}
}
You can pass the token as the sender:
self.performSegue(withIdentifier: "gotoVerification", sender: AuthResponse.token)
Then:
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if let vc = segue.destination as? UserVerification, let token = sender as? String {
vc.tokens = token
print("token \(token)")
}
}

Passing data between controller after method is done executed [SWIFT]

I'm trying to send data across another view controller once a button is pressed (I know this question looks repetitive), however, the button being pressed is processing some data. So when the button is clicked, the other view controller is popped up before the needed actual data is sent. I tried both segue calls (prepare for segue and the calling segue) but none seem to work. Here is my code:
#IBAction func login(sender: Any) {
SparkCloud.sharedInstance().login(withUser: email, password: password) { (error:Error?) -> Void in
if let _ = error {
print("Wrong credentials or no internet connectivity, please try again")
}
else {
print("Logged in")
var myPhoton : SparkDevice?
SparkCloud.sharedInstance().getDevices { (devices:[SparkDevice]?, error:Error?) -> Void in
if let _ = error {
print("Check your internet connectivity")
}
else {
if let d = devices {
for device in d {
myPhoton = device
print(myPhoton!)
}
}
}
}
}
}
}
And the segue:
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "loggedIn" {
if let destinationVC = segue.destination as? testViewController {
destinationVC.myPhoton = sentDevice
}
}
}
And the other view controller that is receiving the data:
var myPhoton : SparkDevice?
override func viewDidLoad() {
super.viewDidLoad()
print(myPhoton)
}
I receive 'nil', which indicates that when the data has been set, it was before it got set to the data that I wanted from the server. Can someone help me please?
You can try
#IBAction func login(sender: Any) {
SparkCloud.sharedInstance().login(withUser: email, password: password) { (error:Error?) -> Void in
if let _ = error {
print("Wrong credentials or no internet connectivity, please try again")
}
else {
print("Logged in")
var myPhoton : SparkDevice?
SparkCloud.sharedInstance().getDevices { (devices:[SparkDevice]?, error:Error?) -> Void in
if let _ = error {
print("Check your internet connectivity")
}
else {
if let d = devices {
for device in d {
myPhoton = device
print(myPhoton!)
}
self.performSegue(withIdentifier: "loggedIn", sender: myPhoton)
}
}
}
}
}
}
and remove linking the segue directly to the button action in IB
Edit
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "loggedIn" {
if let destinationVC = segue.destination as? testViewController {
destinationVC.myPhoton = sender as! SparkDevice
}
}
}
Instead of using Segue, you can also try doing it with code, i.e.
#IBAction func login(_ sender: UIButton)
{
SparkCloud.sharedInstance().login(withUser: email, password: password) {
if let _ = error
{
print("Wrong credentials or no internet connectivity, please try again")
}
else
{
print("Logged in")
var myPhoton : SparkDevice?
SparkCloud.sharedInstance().getDevices { (devices:[SparkDevice]?, error:Error?) -> Void in
if let _ = error
{
print("Check your internet connectivity")
}
else
{
if let d = devices
{
for device in d
{
myPhoton = device
print(myPhoton!)
//HERE..!!!!!
DispatchQueue.main.async {[weak self] in
let anotherController = self.storyboard?.instantiateViewController(withIdentifier: "AnotherVC") as! AnotherVC
anotherController.myPhoton = myPhoton
self.navigationController?.pushViewController(anotherController, animated: true)
}
}
}
}
}
}
}
}
In the above code, if you want to push the controller, then use:
self.navigationController?.pushViewController(anotherController, animated: true)
otherwise, if you want to present the controller, then use:
self.present(anotherController, animated: true, completion: nil)
Let me know if you still face any issues.

How to Segue from a AVPlayer recording to a new Controller?

I have this Delegate in my CameraViewController. It calls fileOutput when its done capturing a video. I want to pass the url of the captured video to my next view controller in my storyboard where I show the captured file:
extension CameraViewController: AVCaptureFileOutputRecordingDelegate{
func fileOutput(_ output: AVCaptureFileOutput, didFinishRecordingTo outputFileURL: URL, from connections: [AVCaptureConnection], error: Error?) {
let destinationVC = PreviewViewController()
if (error != nil) {
print("Error recording movie: \(error!.localizedDescription)")
} else {
let videoRecorded = outputURL! as URL
}
outputURL = nil }
override func prepare(for segue: UIStoryboardSegue, sender: Any?){
if segue.identifier == "showCapture_Segue" {
let controller = segue.destination as! CameraPreviewController
controller.movieURL = videoRecorded
}
}
}
This is my code right now. There are a lot of complaints from Xcode and it doesn't make sense as Im not passing the videoRecorded from the fileOutput function into the segue override function.
I know to create a segue and pass data into another view controller I do something like
override func prepare(for segue: UIStoryboardSegue, sender: Any?){
if segue.identifier == "showCapture_Segue" {
let controller = segue.destination as! CameraPreviewController
controller.movieURL = videoRecorded
}
}
But I'm not sure how this integrates with my AVCaptureFileOutputRecordingDelegate. How can I do this? Thanks!
Edit:
class CameraViewController: UIViewController {
var outputURL: URL!
func startRecording() {
if movieOutput.isRecording == false {
let connection = movieOutput.connection(with: AVMediaType.video)
if (connection?.isVideoOrientationSupported)! {
connection?.videoOrientation = currentVideoOrientation()
}
if (connection?.isVideoStabilizationSupported)! {
connection?.preferredVideoStabilizationMode = AVCaptureVideoStabilizationMode.auto
}
let device = activeInput.device
if (device.isSmoothAutoFocusSupported) {
do {
try device.lockForConfiguration()
device.isSmoothAutoFocusEnabled = false
device.unlockForConfiguration()
} catch {
print("Error setting configuration: \(error)")
}
}
//EDIT2: And I forgot this
outputURL = tempURL()
movieOutput.startRecording(to: outputURL, recordingDelegate: self)
}
else {
stopRecording()
}
}
}
You should declare as instance value
class CameraViewController {
var videoRecorded:URL?
}
//
extension CameraViewController: AVCaptureFileOutputRecordingDelegate{
func fileOutput(_ output: AVCaptureFileOutput, didFinishRecordingTo outputFileURL: URL, from connections: [AVCaptureConnection], error: Error?) {
let destinationVC = PreviewViewController()
if (error != nil) {
print("Error recording movie: \(error!.localizedDescription)")
} else {
self.videoRecorded = outputURL as! URL
}
outputURL = nil }
override func prepare(for segue: UIStoryboardSegue, sender: Any?){
if segue.identifier == "showCapture_Segue" {
let controller = segue.destination as! CameraPreviewController
controller.movieURL = self.videoRecorded
}
}
}
//
class CameraPreviewController {
var movieURL:URL?
}
//
self.performSegue(withIdentifier: "showCapture_Segue", sender: nil)

Pass data depends on the button in tableView cell

I have a TableView where I display all my data and each cell might have 1-2 buttons. I read many topics and understand how to add target for each button through my ViewController. Since these buttons will be forwarded to the same VC and display images, I have the following code. In my TableViewCell subclass I have 2 buttons
class CODetailsTicketCell: UITableViewCel {
var onButtonTapped: (() -> Void)? = nil
#IBAction func firstBtnTapped(_ sender: UIButton) {
if let onButtonTapped = self.onButtonTapped {
onButtonTapped()
}
print("First button was pressed")
}
#IBAction func secondBtnTapped(_ sender: UIButton) {
if let onButtonTapped = self.onButtonTapped {
onButtonTapped()
}
print("Second button was pressed")
}
}
In my ViewController in cellForRowAt indexPath I have the following code
let message = messages[indexPath.row]
if let cell = tableView.dequeueReusableCell(withIdentifier: "COTicketsCell", for: indexPath) as? CODetailsTicketCell {
cell.configureCell(openTickets: message)
cell.onButtonTapped = {
self.performSegue(withIdentifier: "toImageVC", sender: message)
}
return cell
In order to pass the data through segue I use the following code in prepareForSegue
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "toImageVC" {
let navigationController = segue.destination as? UINavigationController
if let targetController = navigationController?.topViewController as? ImageVC {
if let data = sender as? OpenTicketsData {
targetController.loadImageURL = URL(string: data.firstImageUrl)
}
}
}
}
Everything is working FINE but I can't check for button tag in prepareForSegue. Basically, currently both buttons send the same data
targetController.loadImageURL = URL(string: data.firstImageUrl)
How can I pass data based on the button pressed? I tried to do something like this but seems it's wrong and not working.
let button = sender as? UIButton
if let data = sender as? OpenTicketsData {
if button?.tag == 1 {
targetController.loadImageURL = URL(string: data.firstImageUrl)
} else if button?.tag == 2 {
targetController.loadImageURL = URL(string: data.secondImageUrl)
}
}
You can either separate it into 2 different events or
class CODetailsTicketCell: UITableViewCell {
var onButtonTapped: ((_ sender: UIButton) -> Void)? = nil
#IBAction func firstBtnTapped(_ sender: UIButton) {
if let onButtonTapped = self.onButtonTapped {
onButtonTapped?(sender)
}
print("First button was pressed")
}
#IBAction func secondBtnTapped(_ sender: UIButton) {
if let onButtonTapped = self.onButtonTapped {
onButtonTapped(sender)
}
print("Second button was pressed")
}
}
In your assignment of the onButtonTapped, remember to add [weak self] if you ever use self to avoid the retain cycle.
cell.onButtonTapped = { [weak self] sender in
if sender.tag == 1 {
// Do something
} else {
// Do other thing
}
}

Swift 3 Unable to make phone call with the String transferred from the tableviewcell

Thanks for the help in advance. I don't know why when I try to make a phone call with a button function as below
#IBAction func phonebutton(_ sender: Any) {
guard let number1 = URL(string: "telprompt://\(phonenumber)") else { return }
UIApplication.shared.open(number1 as! URL, options: [:], completionHandler: nil)
}
it doesn't show anything.
To explain more, the String value "phonenumber" is transferred from another tableview cell prepare for segue function as below
override func prepare(for segue: UIStoryboardSegue, sender: Any? ) {
if (segue.identifier == "indooradventureseg"){
let transfertopage = segue.destination as! indooradventuretablecellViewController
transfertopage.phonenumber = info[sender as! Int][4] as! String
}
Here's the code in the ViewController where I put my call button in
class indooradventuretablecellViewController: UIViewController {
var phonenumber = "31617543"
override func viewDidLoad() {
super.viewDidLoad()
phonenumberlabel.text = phonenumber
phonebuttonlabel.setTitle(phonenumber, for: .normal)
}
However, if I put any other String initiated within the ViewController or simply put the phone number on the button function like below, the phone call function does work.
#IBAction func phonebutton(_ sender: Any) {
guard let number1 = URL(string: "telprompt://12345678") else { return }
UIApplication.shared.open(number1 as! URL, options: [:], completionHandler: nil)
}
Please help. Thanks!

Resources