I am trying to send a mail from the collection view cell controller, but I get error. Here is full code:
import Foundation
import UIKit
import MessageUI
import Parse
import Bolts
class CollectionViewCell: UICollectionViewCell, MFMailComposeViewControllerDelegate {
#IBOutlet weak var imageView: UIImageView!
#IBOutlet weak var imageText: UILabel!
#IBOutlet weak var uploadedTimeLabel: UILabel!
#IBOutlet weak var currentUserLabel: UILabel!
#IBOutlet weak var flagContentButton: UIButton!
var deviceID = [String]()
var parseObject:PFObject?
#IBAction func buttonClick(sender: AnyObject) {
println(deviceID)
let mailComposeViewController = configuredMailComposeViewController()
if MFMailComposeViewController.canSendMail() {
self.presentViewController(mailComposeViewController, animated: true, completion: nil)
} else {
self.showSendMailErrorAlert()
}
}
func configuredMailComposeViewController() -> MFMailComposeViewController {
let mailComposerVC = MFMailComposeViewController()
mailComposerVC.mailComposeDelegate = self // Extremely important to set the --mailComposeDelegate-- property, NOT the --delegate-- property
mailComposerVC.setToRecipients(["test#email.com"])
mailComposerVC.setSubject("Test subject")
mailComposerVC.setMessageBody("Test mail!", isHTML: false)
return mailComposerVC
}
func showSendMailErrorAlert() {
let sendMailErrorAlert = UIAlertView(title: "Could Not Send Email", message: "Your device could not send e-mail. Please check e-mail configuration and try again.", delegate: self, cancelButtonTitle: "OK")
sendMailErrorAlert.show()
}
// MARK: MFMailComposeViewControllerDelegate
func mailComposeController(controller: MFMailComposeViewController!, didFinishWithResult result: MFMailComposeResult, error: NSError!) {
controller.dismissViewControllerAnimated(true, completion: nil)
}
}
Error line:
self.presentViewController(mailComposeViewController, animated: true, completion: nil)
Error code:
'CollectionViewCell' does not have a member named
'presentViewController'
Any suggestions what to do here?
You could use completion blocks or a delegate to notify the view controller, like below. You would set either delegate or notifyViewController on the cell in your cellForItemAtIndexPath. This way, you can tell each cell which controller you want to handle presenting the mail controller and the controller can decide how to do it.
protocol CollectionViewCellDelegate {
func notifyViewController(mailViewController: MFMailComposeViewController)
}
class CollectionViewCell: ... {
//...
var delegate: CollectionViewCellDelegate?
// you could use this completion block property in place of a delegate
var notifyViewController: ((MFMailComposeViewController) -> Void)?
//...
#IBAction func buttonClick(sender: AnyObject) {
println(deviceID)
let mailComposeViewController = configuredMailComposeViewController()
if MFMailComposeViewController.canSendMail() {
delegate?.notifyViewController(mailComposeViewController)
// OR
notifyViewController?(mailComposeViewController)
} else {
self.showSendMailErrorAlert()
}
}
//...
}
Related
I'm struggling to get an optional type to a Label.text. It keeps on giving me "nil" value and won't change the text.
import UIKit
class VerifyPNViewController: UIViewController {
#IBOutlet weak var VerificationMessage: UILabel!
#IBAction func backButton(_ sender: Any) {
self.view.window!.rootViewController?.dismiss(animated: true, completion: nil)
}
override func viewDidLoad() {
super.viewDidLoad()
}
func didSuccess(_ response: GetLoginVerificationMessage){
let Main = response.result!
DispatchQueue.main.async {
print(Main)
self.VerificationMessage?.text = Main
print(self.VerificationMessage?.text)
}
}
}
and I will get a
234443 << which is a response.result!
nil << print(self.VerificationMessage?.text)
I have no idea why this value won't go into the "self. Verification?.text" Does anyone have ideas?
Thank you.
I am working on an open source application using Xcode 9.3.1 Swift 4.
There is a play button. When the user clicks on the play button the audio file downloads automatically before it starts playing. I want to add an alert message that alerts the user, shows the file size, and lets him accept or not to proceed with the download.
Here my audiobarview.xib code:
import GenericDataSources
import QueuePlayer
import UIKit
internal protocol AdvancedAudioOptionsViewControllerDelegate : AnyObject {
internal func advancedAudioOptionsViewController(_ controller: AdvancedAudioOptionsViewController, finishedWith options: AdvancedAudioOptions)
}
internal class AdvancedAudioOptionsViewController : UIViewController, UIGestureRecognizerDelegate {
weak internal var delegate: AdvancedAudioOptionsViewControllerDelegate?
#IBOutlet weak internal var tableView: UITableView!
#IBOutlet weak internal var contentView: UIView!
#IBOutlet weak internal var bottomConstraint: NSLayoutConstraint!
#IBOutlet weak internal var navigationBar: UINavigationBar!
lazy internal var playButton: UIButton { get set }
internal init(options: AdvancedAudioOptions)
required internal init?(coder aDecoder: NSCoder)
override internal func viewDidLoad()
override internal func viewDidAppear(_ animated: Bool)
override internal func viewDidLayoutSubviews()
#IBAction internal func playButtonTapped(_ sender: Any)
#IBAction internal func dismissView(_ sender: Any)
internal func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldReceive touch: UITouch) -> Bool
}
extension UIView {
internal func round(corners: UIRectCorner, radius: CGFloat)
}
Here is the audiofilesdownloader.swift code:
import BatchDownloader
import PromiseKit
class AudioFilesDownloader {
let audioFileList: QariAudioFileListRetrieval
let downloader: DownloadManager
let ayahDownloader: AnyInteractor<AyahsAudioDownloadRequest, DownloadBatchResponse>
private var response: DownloadBatchResponse?
init(audioFileList: QariAudioFileListRetrieval,
downloader: DownloadManager,
ayahDownloader: AnyInteractor<AyahsAudioDownloadRequest, DownloadBatchResponse>) {
self.audioFileList = audioFileList
self.downloader = downloader
self.ayahDownloader = ayahDownloader
}
func cancel() {
response?.cancel()
response = nil
}
func needsToDownloadFiles(qari: Qari, range: VerseRange) -> Bool {
let files = filesForQari(qari, range: range)
return !files.filter { !FileManager.documentsURL.appendingPathComponent($0.destinationPath).isReachable }.isEmpty
}
func getCurrentDownloadResponse() -> Promise<DownloadBatchResponse?> {
if let response = response {
return Promise(value: response)
} else {
return downloader.getOnGoingDownloads().then { batches -> DownloadBatchResponse? in
let downloading = batches.first { $0.isAudio }
self.createRequestWithDownloads(downloading)
return self.response
}
}
}
func download(qari: Qari, range: VerseRange) -> Promise<DownloadBatchResponse?> {
return ayahDownloader
.execute(AyahsAudioDownloadRequest(range: range, qari: qari))
.then(on: .main) { responses -> DownloadBatchResponse? in
// wrap the requests
self.createRequestWithDownloads(responses)
return self.response
}
}
private func createRequestWithDownloads(_ batch: DownloadBatchResponse?) {
guard let batch = batch else { return }
response = batch
response?.promise.always { [weak self] in
self?.response = nil
}
}
func filesForQari(_ qari: Qari, range: VerseRange) -> [DownloadRequest] {
return audioFileList.get(for: qari, range: range).map {
DownloadRequest(url: $0.remote, resumePath: $0.local.stringByAppendingPath(Files.downloadResumeDataExtension), destinationPath: $0.local)
}
}
}
Assuming you have the filesize as a variable filesize
Swift 4:
let alert = UIAlertController(title: "Proceed with download?", message: "File size: \(filesize)", preferredStyle: .alert)
alert.addAction(UIAlertAction(title: "Cancel", style: .cancel, handler: {(alert: UIAlertAction!) in
// Leave empty, dismisses the alert
}))
alert.addAction(UIAlertAction(title: "Download Song", style: .default, handler: {(alert: UIAlertAction!) in
// Code to download song
}))
self.present(alert, animated: true, completion: nil)
I would like to make the "Leave a Suggestion" static cell open the mail and allow me to compose a message with a set subject. How would I accomplish this?
EDIT:
import UIKit
import MessageUI
class AccountViewController: UITableViewController, MFMailComposeViewControllerDelegate {
#IBOutlet var Logout: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
#IBAction func emailButtonAction(_ sender: UIButton) {
if MFMailComposeViewController.canSendMail() {
let mail = MFMailComposeViewController()
mail.mailComposeDelegate = self
mail.setToRecipients(["example#gmail.com"])
mail.setSubject("Example Subject")
mail.setMessageBody("<p>Test</p>", isHTML: true)
present(mail, animated: true)
}
}
func mailComposeController(_ controller: MFMailComposeViewController, didFinishWith result: MFMailComposeResult, error: Error?) {
controller.dismiss(animated: true)
}
}
UIButton does not work with any of my cells
In the code below I have a ViewController("SenderViewController"), which passes a message to the main ViewController when a button is tapped. What I don't fully understand is how does messageData() method in the main ViewController know when to listen for the message.
Can someone please explain me what is triggering the messageData() method in the main ViewController?
SenderViewController:
import UIKit
protocol SenderViewControllerDelegate {
func messageData(data: AnyObject)
}
class SenderViewController: UIViewController {
#IBOutlet weak var inputMessage: UITextField!
var delegate: SenderViewControllerDelegate?
#IBAction func sendData(sender: AnyObject) {
/
if inputMessage.text != ""{
self.presentingViewController!.dismissViewControllerAnimated(true, completion: nil)
self.delegate?.messageData(inputMessage.text!)
}
}
}
Main ViewController:
import UIKit
class ViewController: UIViewController, SenderViewControllerDelegate{
#IBOutlet weak var showData: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
}
#IBAction func goToView(sender: AnyObject) {
let pvc = storyboard?.instantiateViewControllerWithIdentifier("senderViewController") as! SenderViewController
pvc.delegate = self
self.presentViewController(pvc, animated:true, completion:nil)
}
// What triggers this method, how it know when to listen?
func messageData(data: AnyObject) {
self.showData.text = "\(data)"
}
}
Thanks a lot!
Objects don't exactly listen for method calls. They sit there, waiting to invoked.
The line
self.delegate?.messageData(inputMessage.text!)
From your SenderViewController is a function call. (The term method and function are pretty much interchangeable, although the method is usually used for the functions of objects.) It invokes the function messageData in ViewController.
While Presenting SenderViewController from MainViewController you are setting the delegate as self. So whenever you call the delegate method in SenderViewController
self.delegate?.messageData(inputMessage.text!)
following method of MainViewController will act as a callback
func messageData(data: AnyObject) {
self.showData.text = "\(data)"
}
In SenderViewController:
When you tap button you invoke sendData method. In this method you ask delegate to invoke its messageData method. Delegate property declared as SenderViewControllerDelegate type, so you can do that (see this protocol defenition).
In ViewController (first view controller):
Before you open second view controller, in method goToView you seting up property delegate of SenderViewController to 'myself', to exact instance of ViewController, since you declared that it confirm protocol SenderViewControllerDelegate by implementing method messageData. So, ViewController is now saved as delegate property in SenderViewController, and can be used to invoke messageData!
self.delegate?.messageData(inputMessage.text!)
#IBAction func sendData(sender: AnyObject) {
if inputMessage.text != ""{
self.delegate?.messageData(inputMessage.text!)
self.presentingViewController!.dismissViewControllerAnimated(true, completion: nil)
}else{
//handle here
}
Note: If you need to pass multiple data to mainViewController then use dictionary to pass them. i.e.
SenderViewController:
import UIKit
protocol SenderViewControllerDelegate {
func messageData(data: [String : Any])
}
class SenderViewController: UIViewController {
#IBOutlet weak var inputMessage: UITextField!
var delegate: SenderViewControllerDelegate?
#IBAction func sendData(sender: AnyObject) {
let myDict = [ "name": "Name", "age": 21, "email": "test#gmail.com"] as! [String : Any]
self.delegate?.messageData(myDict)
self.presentingViewController!.dismissViewControllerAnimated(true, completion: nil)
}
}
Main ViewController
import UIKit
class ViewController: UIViewController, SenderViewControllerDelegate{
#IBOutlet weak var showData: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
}
#IBAction func goToView(sender: AnyObject) {
let pvc = storyboard?.instantiateViewControllerWithIdentifier("senderViewController") as! SenderViewController
pvc.delegate = self
self.presentViewController(pvc, animated:true, completion:nil)
}
// What triggers this method, how it know when to listen?
func messageData(data: [String : Any]) {
print(data["name"])
print(data["age"])
print(data["email"])
}
}
when following the instructions for FirebaseUI to display the LoginViewController it only shows a black screen.
As you can see it kind of replaces the current viewcontroller instead of presenting it.
Here is the code from the presenting viewcontroller
import UIKit
import Firebase
import FirebaseUI
class FirstViewController: UIViewController {
#IBOutlet weak var logoutButton: UIButton!
var rootRef = Firebase(url: Constants.FireBaseUrl)
var loginViewController: FirebaseLoginViewController!
override func viewDidLoad() {
super.viewDidLoad()
loginViewController = FirebaseLoginViewController(ref: rootRef)
loginViewController.enableProvider(.Facebook)
loginViewController.enableProvider(.Password)
loginViewController.didDismissWithBlock { (user: FAuthData!, error: NSError!) -> Void in
if (user != nil) {
// user
} else if (error != nil) {
// error
} else {
// cancel
}
}
}
override func viewDidAppear(animated: Bool) {
super.viewDidAppear(animated)
if (loginViewController.currentUser() == nil) {
presentViewController(loginViewController, animated: true, completion: nil)
}
}
// MARK: - Actions
#IBAction func logoutTouched(sender: AnyObject) {
rootRef.unauth()
}
}