Xcode Document Picker Delegate in UIKit - ios

Why cant I set the delegate to self? I'm running the code below in the viewcontroller.swift file, but I want to call it in a Render.swift file. I've got a metal scene running of the camera view and want to open the file picker in front of it, but it doesn't seem to be very simple.
#IBAction func importFiles(_ sender: Any) {
let documentPicker = UIDocumentPickerViewController(documentTypes: [kUTTypePlainText as String], in: .import)
documentPicker.delegate = self
documentPicker.allowsMultipleSelection = false
present(documentPicker, animated: true, completion: nil)
}
It says Cannot assign value of type 'ViewController' to type 'UIDocumentPickerDelegate
In my Renders.swift file I have a function tied to a button that calls the following:
//open dialog for picker...
let myVC: ViewController = ViewController()
myVC.importFiles()
I'm pretty new to this all.

Why cant I set the delegate to self?
Because the delegate needs to be a UIDocumentPickerDelegate, and self is not a UIDocumentPickerDelegate. You need to declare that it is:
class ViewController : UIViewController, UIDocumentPickerDelegate {
That may precipitate other issues (and I expect it will), but at least you'll get past the point where you are now.

Related

Cannot dismiss MFMailComposeViewController that I called from SKScene

I am trying to send an email from within my game app. In one of my SKScenes I have a sprite when you press it, it calls FeedbackVC().sendEmail(). This opens up the email viewController, but it does not dismiss properly. Here is my entire FeedbackVC class. I used the function getTopMostViewController because without it I was getting the error "Warning: Attempt to present on whose view is not in the window hierarchy!". My code will successfully open the MFMailComposeViewController with the prefilled fields and if I press the send button it actually will send to the email to my email, but it won't close and if I try to cancel the email it won't close either. Why won't my viewController close so it will continue back to my game after the email is sent or canceled?
import Foundation
import MessageUI
class FeedbackVC: UINavigationController, MFMailComposeViewControllerDelegate {
func getTopMostViewController() -> UIViewController? {
var topMostViewController = UIApplication.shared.keyWindow?.rootViewController
while let presentedViewController = topMostViewController?.presentedViewController {
topMostViewController = presentedViewController
}
return topMostViewController
}
func sendEmail() {
if MFMailComposeViewController.canSendMail() {
let mail = MFMailComposeViewController()
mail.mailComposeDelegate = self
mail.setToRecipients(["support#supportemail.com"])
mail.setSubject("In-App Feedback")
mail.setMessageBody("", isHTML: false)
self.getTopMostViewController()!.present(mail, animated: true, completion: nil)
} else {
print("Failed To Send Email!")
}
}
func mailComposeController(_ controller: MFMailComposeViewController, didFinishWith result: MFMailComposeResult, error: Error?) {
controller.dismiss(animated: true, completion: nil)
}
}
I have also tried setting the UINavigationControllerDelegate in the sendEmail() function.
mail.delegate = self as? UINavigationControllerDelegate
I have also tried things like popping the view controller and going back to the top most view controller in the mailComposeController.
popToRootViewContoller(animated: true)
getTopMostViewController()?.dismiss(animated: true, completion: nil)
I've tried following the guide on, https://developer.apple.com/documentation/messageui/mfmailcomposeviewcontroller, but it didn't work as I think my scenario is different since I am going from a SKScene to the MFMailCompose ViewController then back to a SKScene.
I'm one of the other developers working on this project. Posting in case someone has similar problems.
We were attempting to call our FeedbackVC in a way that looked like this:
if nodeTapped.name == "Feedback" {
let vc = FeedbackVC()
vc.emailButtonTapped(foo)
}
This would create the FeedbackVC class, call the emailButtonTapped method, and then deallocate the class from memory upon exiting the if statement. This means that clicking cancel or send would attempt to access the deallocated space, causing an EXC_BAD_ACCESS error. I fixed this by declaring vc as a class variable instead of declaring it inside the if statement.

Importing image from photo library into an app in xcode

My app keeps crashing and I don't know why. I'm working on a tabbed application part by part and testing it every time I get a part of it done.
Right now I'm working on trying to import an image from the user's device but I can't seem to get it.
I'm currently using Xcode 10.2.1 and I understand that there has been some changes to the delegate methods and I have changed them. It succeeds in building but whenever I tap that one particular tab where I would like to import an image, it crashes.
class UserImage: UIViewController,UINavigationControllerDelegate, UIImagePickerControllerDelegate {
var imagePickerController : UIImagePickerController!
#IBOutlet var ImageView: UIImageView!
#IBAction func Edit(_ sender: Any) {
imagePickerController.delegate = self
imagePickerController.sourceType = .photoLibrary
present(imagePickerController, animated: true, completion: nil)
}
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any])
{
if let image = info[.originalImage] as? UIImage {
ImageView.image = image
} else {
print("Take another")
}
self.dismiss(animated: true, completion: nil)
}
It is crashing because you never actually initialized the UIImagePickerController. Since you marked the imagePickerController as a non optional value, your app is going to crash when you try to reference it but it is still nil. Add this line to the beginning of your Edit function to initialize the variable:
imagePickerController = UIImagePickerController()
Edit: Alternatively, as #rmaddy mentioned, you could just make the controller a local variable of the function. In your example, there is no need to make it a property of the class. Essentially you would just remove the declaration from the top of your class and instead declare it inside the function:
let imagePickerController = UIImagePickerController()

Use of undeclared type Xcode with Cocoapods

I am trying to refer to the app delegate in a UIButton Action that is in a Pods class in my workspace, however, I keep getting the error "Use of undeclared type". I believe this is due to the App Delegate being in the other workspace project. I would like to know how to fix it? Thank you.
Button Code
#IBAction func buttonAction(sender: AnyObject) {
let paymentViewController = storyboard.instantiateViewControllerWithIdentifier("paymentViewController") as! AddCardViewController
let paymentPageNav = UINavigationController(rootViewController: paymentViewController)
let appDelegate:AppDelegate = UIApplication.sharedApplication().delegate as! AppDelegate
appDelegate.drawerContainer!.centerViewController = paymentPageNav
appDelegate.drawerContainer!.toggleDrawerSide(MMDrawerSide.Left, animated: true, completion: nil)
}
I get use of undeclared type for AddCardViewController, AppDelegate and MMDrawerSide.
Had this problem with casting to custom controls from pods on my project, what solved it for me is to add import statement in the head of the file for my custom controller.
So if for example I am in MainViewController.swift and want to use a custom control/view/lib called MyCustomController imported with CocoaPods I add import MyCustomController after the import UIKit

Picking a song and play from Music app library - Swift 2.0

I just took a basic Swift 2.0 course. I am trying to make an app to select a song from iOS's Music app library and play it. I came across this link which shows how to make media item picker.
import UIKit
import MediaPlayer
class ViewController: UIViewController {
#IBOutlet weak var pickSong: UIButton!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
let mediaPicker = MPMediaPickerController(mediaTypes: .Music)
// mediaPicker.delegate = self
// mediaPicker.prompt = "Select song (Icloud songs must be downloaded to use)"
mediaPicker.allowsPickingMultipleItems = false
mediaPicker.showsCloudItems = false
presentViewController(mediaPicker, animated: true, completion: {})
}
mediaPicker.delegate = self line shows
Cannot assign value of type 'ViewController' to type
'MPMediaPickerControllerDelegate?'
error message. When I blocked it, the app works and allow me to browse songs perfectly.
Question 1: I would like to know what is the use of this line?
Question 2: How to play a song that I picked using this code?
I searched here and other websites for how to play songs. I found people are using
player.play() to play music. I tried that and failed.
ViewController needs to conform to the 'MPMediaPickerControllerDelegate':
//Let other classes know ViewController is a MPMediaPickerControllerDelegate
class ViewController: UIViewController, MPMediaPickerControllerDelegate {
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
let mediaPicker = MPMediaPickerController(mediaTypes: .Music)
mediaPicker.delegate = self
presentViewController(mediaPicker, animated: true, completion: {})
}
Add these methods to conform to MPMediaPickerControllerDelegate:
func mediaPicker(mediaPicker: MPMediaPickerController, didPickMediaItems mediaItemCollection: MPMediaItemCollection) {
//User selected a/an item(s).
for mpMediaItem in mediaItemCollection.items {
print("Add \(mpMediaItem) to a playlist, prep the player, etc.")
}
}
func mediaPickerDidCancel(mediaPicker: MPMediaPickerController) {
print("User selected Cancel tell me what to do")
}
The purpose of
'mediaPicker.delegate = self'
is to setup ViewController to respond to the functions added above. If you don't set the delegate the mediaPicker will still present, but your ViewController won't know the user made an action.
Whenever you set a delegate, make sure the class conforms to the delegate methods. If you don't know the methods, search through Apple's Developer docs for that delegate (ie search for 'MPMediaPickerControllerDelegate') and you'll see all the delegate methods you can add.

Cannot remove Dismiss and SignUp Button from ParseUI

I can't see why my loginViewController continues to have the dismiss X and the Signup button. I don't want either. I thought by simply not including them in my logInController.fields array that they would not appear, but that does not seem to be the case. Any help?
let logInController = PFLogInViewController()
logInController.delegate = self
self.presentViewController(logInController, animated:true, completion: nil)
logInController.fields = [PFLogInFields.UsernameAndPassword, PFLogInFields.LogInButton, PFLogInFields.PasswordForgotten]
I am getting an error that might mean something.
2015-12-22 21:35:29.463 App Name[5737:99658] Warning: Attempt to present <PFLogInViewController: 0x7fd318c56020> on <app name.loginViewController: 0x7fd318d6c120> whose view is not in the window hierarchy!
I figured it out.
Make sure to import ParseUI
You must present your viewController in viewDidAppear not in viewDidLoad.
Here is the code that I am using, it builds and runs fine.
class LoginViewController: PFLogInViewController, PFLogInViewControllerDelegate {
override func viewDidAppear(animated: Bool) {
let logInController = PFLogInViewController()
logInController.delegate = self
logInController.fields = [PFLogInFields.UsernameAndPassword, PFLogInFields.LogInButton, PFLogInFields.PasswordForgotten, PFLogInFields.SignUpButton]
self.presentViewController(logInController, animated:true, completion: nil)
}

Resources