EKEventEditViewController doesn't dismiss - ios

I'm presenting my EKEventEditViewController in a Helper-Class like this:
func showAddAppointmentController(withDate date:Date) {
let eventVC = EKEventEditViewController()
eventVC.editViewDelegate = self
eventVC.eventStore = eventStore
eventVC.event?.title = "Test appointment"
eventVC.event?.startDate = date
eventVC.event?.endDate = date.addingTimeInterval(3600)
UIApplication.shared.keyWindow?.rootViewController?.present(eventVC, animated: true, completion: nil)
}
Everything works fine, the controller is shown, but as soon as I press "Add" or "Cancel", nothing happens but the following console output:
[EKCalendarItemLocationInlineEditItem isSubitemAtIndexSaveable:] - Location Inline Edit Item didn't have a text label on its non conference location cell; will return NO
I've implemented the delegate as follows, but the method isn't called (doesn't print and also the breakpoints don't work)
extension CalendarHelper : EKEventEditViewDelegate {
func eventEditViewController(_ controller: EKEventEditViewController, didCompleteWith action: EKEventEditViewAction) {
print("Delegate called!")
controller.dismiss(animated: true) {
self.delegate?.didFinish()
}
}
}

Ok, the error was somewhere else and my bad. I was creating the CalendarHelper in the code and not holding it as a property of the class, so as soon as the calendar was shown, the helper was deleted and not available anymore as delegate.
private var calendarHelper:CalendarHelper?
override func viewDidLoad() {
super.viewDidLoad()
calendarHelper = CalendarHelper(delegate: self)
}
func showCalendar() {
calendarHelper.showCalendar()
}
instead of
func showCalendar() {
CalendarHelper(delegate: self).showCalendar()
}

Related

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)
}
}

How to create a Cancel button on the screen that selects the file on Swift5?

I am using UIDocumentBrowser to retrieve files. But I am not able to place a back or cancel button in the navigation bar.
I want to make a cancellation button for this but I can't make a cancellation button. How can I solve this problem?
current code
import Foundation
import UIKit
#available(iOS 11.0, *)
class DocumentBrowserViewController : UIDocumentBrowserViewController, UIDocumentBrowserViewControllerDelegate {
override func viewDidLoad() {
super.viewDidLoad()
delegate = self
browserUserInterfaceStyle = .dark
view.tintColor = .white
}
func documentBrowser(_ controller: UIDocumentBrowserViewController, didRequestDocumentCreationWithHandler importHandler: #escaping (URL?, UIDocumentBrowserViewController.ImportMode) -> Void) {
let newDocumentURL: URL? = nil
// Set the URL for the new document here. Optionally, you can present a template chooser before calling the importHandler.
// Make sure the importHandler is always called, even if the user cancels the creation request.
if newDocumentURL != nil {
importHandler(newDocumentURL, .move)
} else {
importHandler(nil, .none)
}
}
func documentBrowser(_ controller: UIDocumentBrowserViewController, didPickDocumentURLs documentURLs: [URL]) {
guard let sourceURL = documentURLs.first else { return }
do{
try presentDocument(at: sourceURL)
} catch {
Log.Debug("\(error)")
}
}
func documentBrowser(_ controller: UIDocumentBrowserViewController, didImportDocumentAt sourceURL: URL, toDestinationURL destinationURL: URL) {
// Present the Document View Controller for the new newly created document
do{
try presentDocument(at: sourceURL)
} catch {
Log.Debug("\(error)")
}
}
func documentBrowser(_ controller: UIDocumentBrowserViewController, failedToImportDocumentAt documentURL: URL, error: Error?) {
// Make sure to handle the failed import appropriately, e.g., by presenting an error message to the user.
}
func presentDocument(at documentURL: URL) throws {
guard documentURL.startAccessingSecurityScopedResource() else {
throw IXError.fileAcessFailed
}
let storyBoard = UIStoryboard(name: "Main", bundle: nil)
let documentViewController = storyBoard.instantiateViewController(withIdentifier: "ViewController") as! ViewController
documentViewController.document = Document(fileURL: documentURL)
}
}
picture of cancellation button that I want
Help me a lot
Thanks in advance.
Do I understand correctly that you want to push a viewController (documentViewController) on the navigation stack and have a back button on the navigationBar that leads you back to your main viewController (DocumentBrowserViewController)? If so first you need to push documentViewController on the current navigation stack.
First of all, does the documentViewController appears?
What I see is that you instantiate a documentViewController, set it's document to Document(...) and end of story. I don't use storyboard but does instantiate presents the viewController?
If you provide more details I will update the answer. But general conclusion is in your presentDocument(...), you need:
self.navigationController?.pushViewController(documentViewController, animated: true)
I learned about the UIDocumentBrowserViewController class and succeeded in adding buttons. But the position of the button is not where I want it to be.
But this has solved my fundamental problem, so I'll end the question.
override func viewDidLoad() {
super.viewDidLoad()
delegate = self
allowsDocumentCreation = false
allowsPickingMultipleItems = false
browserUserInterfaceStyle = .dark
view.tintColor = .white
let cancelbutton = UIBarButtonItem(title: "Cancel", style: .plain, target: self, action: #selector(cancelButton(sender:)))
additionalTrailingNavigationBarButtonItems = [cancelbutton]
}
#objc func cancelButton(sender: UIBarButtonItem) {
dismiss(animated: true, completion: nil)
}

Delegate and Callback not working for passing Model data

I am trying to pass data from a firstVC to a second VC I have tried using delegate but it never worked (did not show required response) so I tried callback too and it now working so I am pasting both lines of code so any help is welcomed
Delegate:
protocol RatingDelegate: class {
func didLoadRating(ratings : [RatingModel])
}
the viewcontroller which the data would be passed from
ViewController A:
var delegate : RatingDelegate?
func showRatings(ratings: [RatingModel]) {
if delegate != nil {
delegate?.didLoadRating(ratings: ratings)
}
}
where the delegate value is supposed to me printed
RatingVC:
extension RatingVC: RatingDelegate {
func didLoadRating(ratings: [RatingModel]) {
log(ratings)
}
}
The callback Version
The view controller that would get the data
var ratingsCallBack: (() -> ([RatingModel]))?
the view controller which the value would be passed from
func showRatings(ratings: [RatingModel]) {
let ratingVC = RatingVC()
ratingVC.ratingsCallBack!() = {[unowned self] in
return ratings
}
}
this how ever throws a response saying
Expression is not assignable: function call returns immutable value
So the FirstVC passes data to RatingVC.
On FirstVC, at the point were you invoke RatingVC you should assign the delegate.
let ratingVC = RatingVC()
self.delegate = ratingVC //Here you specify RatingVC is the delegate variable
self.present(ratingVC, animated: true)
also
if delegate != nil {
}
is unnecessary, just do delegate?.didLoadRating(ratings: ratings) to keep it cleaner
EDIT: For the callback version is the same, just assign the value to the callback before initializing the view controller that sends the data.
It looks strange:
var ratingsCallBack: (() -> ([RatingModel]))?
should be something like this:
var ratingsCallBack: (([RatingModel]) -> ())?
so in case with callback:
class A: UIViewController {
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
let ratingVC = RatingVC()
ratingVC.ratingsCallBack = { arr in
arr.forEach({ (model) in
print(model.rating)
})
}
navigationController?.pushViewController(ratingVC, animated: false)
}
}
class RatingVC: UIViewController {
var ratingsCallBack: (([RatingModel]) -> ())?
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
}
#IBAction private func someButtonAction(_ sender: Any) {
let arr = [RatingModel.init(rating: 5), RatingModel()]
ratingsCallBack?(arr)
}
}
struct RatingModel {
var rating: Int = 1
}
Then when you press "someButton" you get this array in controller "A"

send data back to previous controller from the second controller it displays Google autocomplete search Places

Hello I have a button in FirstVC and in SecondVC I have a search box on navigationBar which is Google Autocomplete search bar in which user types something and it shows the places. What I want is when user clicks the button and secondVC comes, as soon user selects the place, the firstVC should show up with the data selected on secondVC without user presses any action Button.
Before implementing Google autocomplete, I was showing locations from database in TableView and I was redirecting user to first controller by writing some code in didSelectRowAtIndexPath and everything was working fine. its not working here. I'll Paste my code here of what I am doing right now
FirstVC:
class AddRequestTableViewController:GooglePlacesViewControllerDelegate{
func country(place: GMSPlace!) {
dismissKeyboard()
print("Place name: ", place.name)
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject!) {
let destination = segue.destinationViewController as! GooglePlacesViewController
destination.delegate = self
}
}
SecondVC
protocol GooglePlacesViewControllerDelegate {
func country(place: GMSPlace!,departureOrArrivalSegue:Int)
}
class GooglePlacesViewController: UIViewController {
var delegate : GooglePlacesViewControllerDelegate! = nil
var resultsViewController: GMSAutocompleteResultsViewController?
var searchController: UISearchController?
var resultView: UITextView?
var locationManager = CLLocationManager()
var placesClient : GMSPlacesClient?
var departureOrArrivalSegue:Int?
override func viewDidLoad() {
super.viewDidLoad()
//locationManager.startUpdatingLocation()
// locationManager = CLLocationManager()
// locationManager.delegate = self
//locationManager.desiredAccuracy = kCLLocationAccuracyBest
locationManager.requestAlwaysAuthorization()
//locationManager.startUpdatingLocation()
//locationManager.startMonitoringSignificantLocationChanges()
resultsViewController = GMSAutocompleteResultsViewController()
resultsViewController?.delegate = self
searchController = UISearchController(searchResultsController: resultsViewController)
searchController?.searchResultsUpdater = resultsViewController
// Put the search bar in the navigation bar.
searchController?.searchBar.sizeToFit()
self.navigationItem.titleView = searchController?.searchBar
// When UISearchController presents the results view, present it in
// this view controller, not one further up the chain.
self.definesPresentationContext = true
// Prevent the navigation bar from being hidden when searching.
searchController?.hidesNavigationBarDuringPresentation = false
let camera = UIBarButtonItem(barButtonSystemItem: .Done, target: self, action: Selector("btnOpenCamera"))
self.navigationItem.leftBarButtonItem = camera
placesClient = GMSPlacesClient()
run()
}
func run(){
placesClient?.currentPlaceWithCallback({
(placeLikelihoodList: GMSPlaceLikelihoodList?, error: NSError?) -> Void in
if let error = error {
print("Pick Place error: \(error.localizedDescription)")
return
}
if let placeLicklihoodList = placeLikelihoodList {
let place = placeLicklihoodList.likelihoods.first! as GMSPlaceLikelihood
if let place : GMSPlaceLikelihood = place {
print("place is \(place.place.formattedAddress)")
}
}
})
}
}
// Handle the user's selection.
extension GooglePlacesViewController: GMSAutocompleteResultsViewControllerDelegate {
func resultsController(resultsController: GMSAutocompleteResultsViewController!,
didAutocompleteWithPlace place: GMSPlace!) {
searchController?.active = false
// Do something with the selected place.
print("Place name: ", place.name)
print("Place address: ", place.formattedAddress)
print("Place attributions: ", place.attributions)
print("cordinates are \(place.coordinate)")
delegate.country(place)
}
func resultsController(resultsController: GMSAutocompleteResultsViewController!,
didFailAutocompleteWithError error: NSError!){
// TODO: handle the error.
print("Error: ", error.description)
}
// Turn the network activity indicator on and off again.
func didRequestAutocompletePredictionsForResultsController(resultsController: GMSAutocompleteResultsViewController!) {
UIApplication.sharedApplication().networkActivityIndicatorVisible = true
}
func didUpdateAutocompletePredictionsForResultsController(resultsController: GMSAutocompleteResultsViewController!) {
UIApplication.sharedApplication().networkActivityIndicatorVisible = false
}
}
Your delegate method is:
func country(place: GMSPlace!,departureOrArrivalSegue:Int)
but you only called:
delgate.country(place)
Are you not recieving a compiler error? There should be another argument for your delegate call.
Also your 'GooglePlacesViewController' has not declared itself a delegate for the 'resultsViewController'. You called:
resultsViewController?.delegate = self
So your 'GooglePlacesViewController' should look something like this:
class GooglePlacesViewController: UIViewController, GMSAutocompleteResultsViewControllerDelegate {
How you aren't recieving compiler errors is beyond me. Are you using nano?

Sending SMS from Contacts Fails

I am implementing a seemingly trivial and very popular use case where users select a contact, and send them a precomposed SMS.
However, the SMS ViewController dismisses itself automatically. This is easily reproducible.
How do I fix this?
Here's my code:
import UIKit
import MessageUI
import ContactsUI
class ViewController: UIViewController, MFMessageComposeViewControllerDelegate, CNContactPickerDelegate{
let contactPickerViewController = CNContactPickerViewController()
let messageVC = MFMessageComposeViewController()
override func viewDidLoad() {
super.viewDidLoad()
contactPickerViewController.delegate = self
messageVC.messageComposeDelegate = self
}
func contactPicker(picker: CNContactPickerViewController, didSelectContact contact: CNContact) {
if let phoneNumberValue = contact.phoneNumbers.first?.value as? CNPhoneNumber {
if let phoneNumber = phoneNumberValue.valueForKey("digits") as? String {
// Configure message ViewController
messageVC.recipients = [phoneNumber]
messageVC.body = "Yoyoyo"
picker.presentViewController(messageVC, animated: true, completion: nil)
}
}
}
func messageComposeViewController(controller: MFMessageComposeViewController, didFinishWithResult result: MessageComposeResult) {
self.dismissViewControllerAnimated(true, completion: nil)
}
#IBAction func invite(sender: AnyObject) {
self.presentViewController(self.contactPickerViewController, animated: true, completion: nil)
}
}
The problem is that you are asking your picker to present the message view controller. When contactPicker:picker:didSelectContact: method is called, the picker view controller is automatically being dismissed by the system. This means that the view controller is going away and you are trying to use that view controller to present your next view controller.
What you need to do is have "ViewController" in this case present the message view controller. Below is an example of the portion of your code i changed. You'll notice i have a timer there. This is because if you try to present the messageVC right away, nothing will happen because the contacts view controller isn't done dismissing itself yet.
func contactPicker(picker: CNContactPickerViewController, didSelectContact contact: CNContact) {
if let phoneNumberValue = contact.phoneNumbers.first?.value as? CNPhoneNumber {
if let phoneNumber = phoneNumberValue.valueForKey("digits") as? String {
// Configure message ViewController
messageVC.recipients = [phoneNumber]
messageVC.body = "Yoyoyo"
dispatch_async(dispatch_get_main_queue(), { () -> Void in
self.presentViewController(self.messageVC, animated: true, completion: nil)
})
}
}
}

Resources