How to know if user rejected the Location Services in Swift 2 - swift2

I'm trying to make location service app and i have the following code so when the user goes to that view controller he will get an alert of getting the current location.
This is the code
override func viewDidLoad() {
super.viewDidLoad()
// 1. status is not determined
if CLLocationManager.authorizationStatus() == .NotDetermined {
locationManager.requestAlwaysAuthorization()
}
// 2. authorization were denied
else if CLLocationManager.authorizationStatus() == .Denied {
SwiftSpinner.hide()
let alert = UIAlertController(title: "Error with Your Location" , message: "Location services were previously denied. Please enable location services for this app in Settings.", preferredStyle: UIAlertControllerStyle.Alert)
let ok = UIAlertAction(title: "OK", style: UIAlertActionStyle.Default) {
UIAlertAction in
UIApplication.sharedApplication().openURL(NSURL(string: UIApplicationOpenSettingsURLString)!)
}
alert.addAction(ok)
let cancel = UIAlertAction(title: "Back", style: UIAlertActionStyle.Default) {
UIAlertAction in
self.movenav("arxiki")
}
alert.addAction(cancel)
self.presentViewController(alert, animated: true, completion: nil)
}
// 3. we do have authorization
else if CLLocationManager.authorizationStatus() == .AuthorizedAlways {
locationManager.startUpdatingLocation()
}
self.navigationController?.setNavigationBarHidden(false, animated: true)
self.eventsTable.backgroundColor = UIColor.lightGrayColor()
// self.locationManager.requestAlwaysAuthorization()
if CLLocationManager.locationServicesEnabled() {
locationManager.delegate = self
locationManager.desiredAccuracy = kCLLocationAccuracyNearestTenMeters
locationManager.startUpdatingLocation()
}
}
My question is the following.
If the user pushes "Do not authorise" How can i get his option so i can send him back to the previous view controller or to alert him with the message that i have?

In order to catch the user selection you need to declare a CLLocationManager object and implement its delegate (CLLocationManagerDelegate) and use the following method for catching it.
func locationManager(manager: CLLocationManager, didChangeAuthorizationStatus status: CLAuthorizationStatus) {
if status == .Denied || status == .NotDetermined{
// User selected Not authorized
}
}
I assume you have already configured the info.plist with the suitable locations parameters.
Hope it helps!

Related

Square Connect SDK opens a blank page

I am attempting to implement Square Connect iOS SDK, and after implementing and clicking the pay button it opens up the Square Payment app and redirects to a blank page .. have you guys had the same issues ?
My App delegate has the proper section:
func application(_ app: UIApplication, open url: URL, options: [UIApplication.OpenURLOptionsKey : Any] = [:]) -> Bool {
guard let sourceApplication = options[.sourceApplication] as? String,
sourceApplication.hasPrefix("com.squareup.square") else {
return false
}
do {
let response = try SCCAPIResponse(responseURL: url)
if let error = response.error {
// Handle a failed request.
print(error.localizedDescription)
} else {
// Handle a successful request.
}
} catch let error as NSError {
// Handle unexpected errors.
print(error.localizedDescription)
}
return true
}
I have created a proper URL scheme inside the Square portal. Also my view controller has the correct code:
func charge()
{
// connect v1
if let callbackURL = URL(string: "myscheme://")
{
do
{
SCCAPIRequest.setClientID("xxxxxxxxxxx")
let amount = try SCCMoney(amountCents: 100, currencyCode: "USD")
let request = try SCCAPIRequest(
callbackURL: callbackURL,
amount: amount,
userInfoString: nil,
locationID: nil,
notes: "Purchase for cleaning",
customerID: nil, supportedTenderTypes: .all,
clearsDefaultFees: true,
returnAutomaticallyAfterPayment: true)
try SCCAPIConnection.perform(request)
}
catch let error as NSError {
print(error.localizedDescription)
}
}
}
https://snag.gy/R4A30L.jpg
Andrei
You need to make sure you delete all apps from the phone with having duplicate bundle ids. This way you will make sure you go back to the original app which triggered the payment.

Refresh/Reload Eureka PushRow's pushed ViewController options with button?

I am using Eureka forms in my project.
I have a PushRow that presents the default SelectorViewController with a list of options. In the pushed view, I have added a rightBarButtonItem that points to locationSelectorAddButton ... on click, this brings up a UIAlertController that should allow users to add options to this pushed controller.
Is it possible, without creating my own custom selector controller, to refresh the current controller with the newly saved options from UserDefaults?
let defaults = UserDefaults.standard
func setupForm() {
form
+++ PushRow<String>(K.SESSIONFIELD.location) {
$0.title = K.SESSIONFIELD.location
$0.options = defaults.array(forKey: K.SESSIONFIELD.location) as? [String]
$0.value = sessionResult?.sessionLocation ?? $0.options?.first
}
.onPresent { from, to in
to.navigationItem.rightBarButtonItem = UIBarButtonItem(image: UIImage(named:"add_20pt"), style: UIBarButtonItemStyle.plain, target: from, action: #selector(self.locationSelectorAddButton(_:)))
}
}
the locationSelectorAddButton is implemented as follows:
#objc func locationSelectorAddButton(_ sender: UIBarButtonItem) {
var textField = UITextField()
let alert = UIAlertController(title: "Add New Location", message: "", preferredStyle: .alert)
let action = UIAlertAction(title: "Add", style: .default) { (action) in
var locArray = self.defaults.array(forKey: K.SESSIONFIELD.location) as? [String]
locArray?.append(textField.text!)
self.defaults.set(locArray, forKey: K.SESSIONFIELD.location)
///TODO: somehow refresh the pushed view controller here!!
// self.form.rowBy(tag: K.SESSIONFIELD.location)?.reload()
// print("this is the list of locations currently ...\(locArray)")
// self.tableView.reloadData()
///
}
alert.addTextField { (alertTextField) in
alertTextField.placeholder = "Location name ..."
textField = alertTextField
}
alert.addAction(action)
present(alert, animated:true, completion:nil)
}
Push row is not reloaded by using tag property. You need to implement the method
cellUpdate { cell, row in
row.options = (assign value here for updated options)
}

Attempt to present alertcontroller whose view is not in window hierarchy

I'm getting the following error in Swift 3:
Attempt to present alertcontroller whose view is not in window hierarchy
I have already referred to other posts on this topic to no avail. More specifically, I've implemented the change suggested in this post: AlertController is not in the window hierarchy
and I'm still receiving the same error.
What I've done is:
Create an AlertHelper.swift helper class:
class AlertHelper {
func showAlert(fromController controller: UIViewController) {
let alert = UIAlertController(title: "Please Try Again", message: "Email Already In Use", preferredStyle: .alert)
controller.present(alert, animated: true, completion: nil)
}
}
In my View Controller, under a function which is called when a button is pressed, I check to see if an email address entered by a user is already stored in my Firebase database, and if so, I try to present an "Email already in use" alert from the AlertHelper class:
Auth.auth().createUser(withEmail: email, password: password) { (user, error) in
if error != nil {
if let errCode = AuthErrorCode(rawValue: error!._code) {
switch errCode {
case .emailAlreadyInUse:
let alert = AlertHelper()
alert.showAlert(fromController: self)
return
default:
print("other error")
}
}
}
else {
// Inputs user email into database
self.ref.child("Users").child((user?.uid)!).setValue(["Email": email, "Location": ""])
self.performSegue(withIdentifier: "todorm", sender: self)
}
}
The database stuff works, the only thing that isn't appearing is the alert. Any ideas? Thanks!!
It's sort of a strange practice to subclass your alert into a separate class.
You should try making a method in your ViewController class
func showAlert() {
let alert = UIAlertController(title: "Please Try Again", message: "Email Already In Use", preferredStyle: .alert)
self.present(alert, animated: true, completion: nil)
}
Call the method using:
self.showAlert()

TableView not updating

I'm currently struggling with getting my TableView to update after I finish performing some functions called in viewDidLoad and viewDidAppear. I tried using self.tableView.reloadData() at the end of my viewDidLoad but it didn't work and upon reloading the tab, the app would crash.
Here is some of my code (I'm trying to fetch events from a Google Calendar and display it in a TableView). I'm trying to display an array of strings named listOfEvents and it is being populated after the tableView is already loaded.
I also tried adding self.tableView.reloadData() at the end of my fetchEvents() but it also killed my app upon reloading the tab
class CalendarViewController: UITableViewController {
var listOfEvents: [String] = []
private let kKeychainItemName = "Google Calendar API"
private let kClientID = "clientID"
// If modifying these scopes, delete your previously saved credentials by
// resetting the iOS simulator or uninstall the app.
private let scopes = [kGTLAuthScopeCalendarReadonly]
private let service = GTLServiceCalendar()
let output = UITextView()
// When the view loads, create necessary subviews
// and initialize the Google Calendar API service
override func viewDidLoad() {
super.viewDidLoad()
if let auth = GTMOAuth2ViewControllerTouch.authForGoogleFromKeychainForName(
kKeychainItemName,
clientID: kClientID,
clientSecret: nil) {
service.authorizer = auth
}
}
// When the view appears, ensure that the Google Calendar API service is authorized
// and perform API calls
override func viewDidAppear(animated: Bool) {
if let authorizer = service.authorizer,
canAuth = authorizer.canAuthorize where canAuth {
fetchEvents()
} else {
presentViewController(
createAuthController(),
animated: true,
completion: nil
)
}
}
// Construct a query and get a list of upcoming events from the user calendar
func fetchEvents() {
let query = GTLQueryCalendar.queryForEventsListWithCalendarId("primary")
query.maxResults = 10
query.timeMin = GTLDateTime(date: NSDate(), timeZone: NSTimeZone.localTimeZone())
query.singleEvents = true
query.orderBy = kGTLCalendarOrderByStartTime
service.executeQuery(
query,
delegate: self,
didFinishSelector: "displayResultWithTicket:finishedWithObject:error:"
)
}
// Display the start dates and event summaries in the UITextView
func displayResultWithTicket(
ticket: GTLServiceTicket,
finishedWithObject response : GTLCalendarEvents,
error : NSError?) {
if let error = error {
showAlert("Error", message: error.localizedDescription)
return
}
var eventString = ""
if let events = response.items() where !events.isEmpty {
for event in events as! [GTLCalendarEvent] {
let start : GTLDateTime! = event.start.dateTime ?? event.start.date
let startString = NSDateFormatter.localizedStringFromDate(
start.date,
dateStyle: .ShortStyle,
timeStyle: .ShortStyle
)
eventString += "\(startString) - \(event.summary)\n"
// An array holding all my upcoming events
listOfEvents.append("\(startString) - \(event.summary)")
print(listOfEvents)
}
} else {
eventString = "No upcoming events found."
}
output.text = eventString
self.tableView.reloadData()
}
// Creates the auth controller for authorizing access to Google Calendar API
private func createAuthController() -> GTMOAuth2ViewControllerTouch {
let scopeString = scopes.joinWithSeparator(" ")
return GTMOAuth2ViewControllerTouch(
scope: scopeString,
clientID: kClientID,
clientSecret: nil,
keychainItemName: kKeychainItemName,
delegate: self,
finishedSelector: "viewController:finishedWithAuth:error:"
)
}
// Handle completion of the authorization process, and update the Google Calendar API
// with the new credentials.
func viewController(vc : UIViewController,
finishedWithAuth authResult : GTMOAuth2Authentication, error : NSError?) {
if let error = error {
service.authorizer = nil
showAlert("Authentication Error", message: error.localizedDescription)
return
}
service.authorizer = authResult
dismissViewControllerAnimated(true, completion: nil)
}
// Helper for showing an alert
func showAlert(title : String, message: String) {
let alert = UIAlertController(
title: title,
message: message,
preferredStyle: UIAlertControllerStyle.Alert
)
let ok = UIAlertAction(
title: "OK",
style: UIAlertActionStyle.Default,
handler: nil
)
alert.addAction(ok)
presentViewController(alert, animated: true, completion: nil)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
print(self.listOfEvents.count)
return self.listOfEvents.count
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = self.tableView.dequeueReusableCellWithIdentifier("Events Cell", forIndexPath: indexPath) as UITableViewCell
var event = ""
event = listOfEvents[indexPath.row]
cell.textLabel?.text = event
return cell
}
}
I would appreciate any help and insight :-) Thanks so much!
After output.text = eventString, you should reload the tableview.

Send email In-game using sprite kit in xcode 7 beta3?

I am making an iPad game in sprite kit using swift in xcode 7beta3 and I want the results of the game to be send to the users email after the game is completed. The user should press a button called send and redirect to where they can type in their email-address and send the message. But I have no idea how to make and send an email.
I have been searching all around the internet for an answer to this question, but all are older version answers. I hope you can help.
Thanks in advance
EDIT:
I have been searching some more and i found a solution (here: http://kellyegan.net/sending-files-using-swift/), but I still have a problem. In my GameViewController i have added:
override func viewDidLoad() {
super.viewDidLoad()
let scene = StartGameScene(size: view.bounds.size)
let skView = view as! SKView
skView.showsFPS = true
skView.showsNodeCount = true
skView.ignoresSiblingOrder = true
scene.scaleMode = .ResizeFill
skView.presentScene(scene)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
internal func sendEmail() {
//Check to see the device can send email.
if( MFMailComposeViewController.canSendMail() ) {
print("Can send email.")
let mailComposer = MFMailComposeViewController()
mailComposer.mailComposeDelegate = self
//Set the subject and message of the email
mailComposer.setSubject("Have you heard a swift?")
mailComposer.setMessageBody("This is what they sound like.", isHTML: false)
if let filePath = NSBundle.mainBundle().pathForResource("Math", ofType: "txt") {
print("File path loaded.")
if let fileData = NSData(contentsOfFile: filePath) {
print("File data loaded.")
mailComposer.addAttachmentData(fileData, mimeType: "text/plain", fileName: "Math")
}
}
self.presentViewController(mailComposer, animated: true, completion: nil)
}
}
func mailComposeController(controller: MFMailComposeViewController, didFinishWithResult result: MFMailComposeResult, error: NSError?) {
self.dismissViewControllerAnimated(true, completion: nil)
}
The sendMail() is called in one of my gameScenes when you press a button.
The problem is that I get an error when I press that button. It prints out
Can send email.
File path loaded.
File data loaded.
as it should, but then it gives an error:
Could not cast value of type 'UIView' (0x1964ea508) to 'SKView' (0x19624f560).
I think the problem is the self.presentViewController(), but I have no idea how to fix it.

Resources