alert controller not displaying in iphone using swift2 - ios

in my app i want to use alert controller so am using the following code:
import UIKit
import CoreLocation
class GPSTrackingManager: NSObject,CLLocationManagerDelegate {
var locationManager: CLLocationManager!
var seenError : Bool = false
func startTracking() {
locationManager = CLLocationManager()
locationManager.delegate = self
locationManager.desiredAccuracy = kCLLocationAccuracyBest
locationManager.requestAlwaysAuthorization()
locationManager.startUpdatingLocation()
}
func locationManager(manager: CLLocationManager, didFailWithError error: NSError) {
locationManager.stopUpdatingLocation()
print("error occured:\(error)")
}
func locationManager(manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
//println("locations = \(locationManager)")
let latValue = locationManager.location!.coordinate.latitude
let lonValue = locationManager.location!.coordinate.longitude
print(latValue)
print(lonValue)
GoogleLat = latValue
GoogleLong = lonValue
CLGeocoder().reverseGeocodeLocation(manager.location!, completionHandler: {(placemarks, error)->Void in
if (error != nil)
{
print("Reverse geocoder failed with error" + error!.localizedDescription)
return
}
if placemarks!.count > 0
{
let pm = placemarks![0] as CLPlacemark
self.displayLocationInfo(pm)
}
else
{
print("Problem with the data received from geocoder")
}
})
}
func displayLocationInfo(placemark: CLPlacemark?)
{
if let containsPlacemark = placemark
{
locationManager.stopUpdatingLocation()
let fourthcity = (containsPlacemark.subAdministrativeArea != nil) ? containsPlacemark.subAdministrativeArea : ""
let fourthState = (containsPlacemark.administrativeArea != nil) ? containsPlacemark.administrativeArea : ""
let fourthCountry = (containsPlacemark.country != nil) ? containsPlacemark.country : ""
print("my Real City = \(fourthcity)")
let fullName = fourthcity
let fullNameArr = fullName!.characters.split{$0 == " "}.map(String.init)
fullNameArr[0]
print(fullNameArr[0])
print("myState = \(fourthState)")
print("myCountry = \(fourthCountry)")
appDelCityname = fullNameArr[0]
appDelStateName = fourthState
appDelCountryName = fourthCountry
print("AppDelegate City Name = \(appDelCityname)")
}
}
func locationManager(manager: CLLocationManager, didChangeAuthorizationStatus status: CLAuthorizationStatus) {
switch status {
case .NotDetermined:
// If status has not yet been determied, ask for authorization
manager.requestWhenInUseAuthorization()
break
case .AuthorizedWhenInUse:
// If authorized when in use
print("AuthorizedWhenInUse")
manager.startUpdatingLocation()
break
case .AuthorizedAlways:
// If always authorized
print("AuthorizedAlways")
manager.startUpdatingLocation()
break
case .Denied:
// If user denied your app access to Location Services, but can grant access from Settings.app
print("user denied to allow")
dispatch_async(dispatch_get_main_queue(), {
NSTimer.scheduledTimerWithTimeInterval(3.0,target: self, selector: #selector(self.DisplayalertToturnonLocation), userInfo: nil, repeats: false)
})
break
default:
print("user cant allow location service")
break
}
}
func DisplayalertToturnonLocation(){
let alertController = UIAlertController(title: "GPRS is Required", message: "This app requires your location,please turn on your location service or set your address", preferredStyle: .Alert)
let saveAction = UIAlertAction(title: "Set Address", style: UIAlertActionStyle.Default, handler: {
alert -> Void in
self.alertTogetAdrressFromUser()
})
alertController.addAction(saveAction)
let cancelAction = UIAlertAction(title: "Settings", style: UIAlertActionStyle.Default, handler: {
(action : UIAlertAction!) -> Void in
UIApplication.sharedApplication().openURL(NSURL(string: UIApplicationOpenSettingsURLString)!)
})
alertController.addAction(cancelAction)
let keyWindow = UIApplication.sharedApplication().keyWindow
let mainController = keyWindow!.rootViewController!
mainController.presentViewController(alertController, animated: true, completion: nil)
}
}
I am calling this function in AppDelegate which executes well in iPad but not in iPhone also it not shows any error or warning and am feeling too difficult to find what am doing wrong here so any one help me to display alert controller in iPhone.
in AppDelegate:
var tracking = GPSTrackingManager()
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
tracking.startTracking()
}

in here you need to follow two things . 1. your code is fine you need to show ur alertcontroller using main thread, else find the root wihch one is most top presnt your alert, else check once your current window is visible or not
present your UIAlertcontroller in Main thread, for e.g
Swift3
DispatchQueue.main.async {
self.tracking.DisplayalertToturnonLocation()
}
swift2
dispatch_async(dispatch_get_main_queue()) {
self.tracking.DisplayalertToturnonLocation()
}
you get the output as
full code
class GPSTrackingManager: NSObject {
func DisplayalertToturnonLocation(){
let alertController = UIAlertController(title: "GPRS is Required", message: "This app requires your location,please turn on your location service or set your address", preferredStyle: .alert)
let saveAction = UIAlertAction(title: "Set Address", style: UIAlertActionStyle.default, handler: {
alert -> Void in
// self.alertTogetAdrressFromUser()
})
alertController.addAction(saveAction)
let cancelAction = UIAlertAction(title: "Settings", style: UIAlertActionStyle.default, handler: {
(action : UIAlertAction!) -> Void in
// UIApplication.shared.openURL(NSURL(string: UIApplicationOpenSettingsURLString)! as URL)
})
alertController.addAction(cancelAction)
UIApplication.shared.keyWindow?.rootViewController?.present(alertController, animated: true, completion: nil)
}
}

Related

How we can send the location messages using firebase in Swift

I want to send the location messages using firebase. like when user click on button it shows alert which message you want to send like audio,video,location.When user select the location from the given option it will call locationViewController and store the location in firebase.I've simple loaded the google map with marker pin point and defined the coordinates it's self not dynamically. InputActionSheet func that defined in chatViewController when user tap on choose button this function call and inside another function call that will call the functionality of location messages.But I'm confused how we get get coordinates dynamically when user taped on any location on google map and also it will show the marker when user tap.
SimpleViewController class for checking the functionality of google map it's working fine:
class ViewController: UIViewController {
#IBOutlet weak var mapView: GMSMapView!
let manager = CLLocationManager()
let karachi = CLLocationCoordinate2D(latitude: 24.882752, longitude: 67.149848)
let tandoAdam = CLLocationCoordinate2D(latitude: 25.76284, longitude: 68.66087)
override func viewDidLoad() {
super.viewDidLoad()
self.setupMap(title: "Karachi", subtitle: "Shah Faisal", karachi)
self.setupMap(title: "TDM", subtitle: "AK H", tandoAdam)
self.mapView.mapStyle(name:"darkTheme", type:"json")
}
func setupMap(title:String,subtitle:String,_ coordinate:CLLocationCoordinate2D){
manager.delegate = self
manager.requestWhenInUseAuthorization()
manager.startUpdatingLocation()
let camera = GMSCameraPosition.camera(withLatitude: coordinate.latitude, longitude: coordinate.longitude, zoom: 6.0)
mapView.camera = camera
mapView.camera = camera
self.addMarker(title: title, subtitle: subtitle, coordinate:coordinate)
}
func addMarker(title:String,subtitle:String,coordinate:CLLocationCoordinate2D){
let marker = GMSMarker()
marker.icon = #imageLiteral(resourceName: "DiceFive")
marker.position = coordinate
marker.title = title
marker.snippet = subtitle
marker.map = mapView
}
}
extension UIViewController : CLLocationManagerDelegate {
public func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
guard locations.first != nil else{
return
}
}
}
presentInputActionSheet func in Chat class:
private func presentInputActionSheet() {
let actionSheet = UIAlertController(title: "Attach Media",
message: "What would you like to attach?",
preferredStyle: .actionSheet)
actionSheet.addAction(UIAlertAction(title: "Photo", style: .default, handler: { [weak self] _ in
self?.presentPhotoInputActionsheet()
}))
actionSheet.addAction(UIAlertAction(title: "Video", style: .default, handler: { [weak self] _ in
self?.presentVideoInputActionsheet()
}))
actionSheet.addAction(UIAlertAction(title: "Audio", style: .default, handler: { _ in
}))
actionSheet.addAction(UIAlertAction(title: "Location", style: .default, handler: { [weak self] _ in
self?.presentLocationPicker()
}))
actionSheet.addAction(UIAlertAction(title: "Cancel", style: .cancel, handler: nil))
present(actionSheet, animated: true)
}
presentLocationPicker func in Chat class:
private func presentLocationPicker() {
let vc = ViewController(coordinates: nil)
vc.title = "Pick Location"
vc.navigationItem.largeTitleDisplayMode = .never
let location = Location(location: CLLocation(latitude: latitude, longitude: longitude),
size: .zero)
let message = Message(sender: selfSender,messageId: messageId,sentDate: Date(),kind: .location(location))
DatabaseManager.shared.sendMessage(to: conversationId, otherUserEmail: strongSelf.otherUserEmail, name: name, newMessage: message, completion: { success in
if success {
print("sent location message")
}
else {
print("failed to send location message")
}
})
}
navigationController?.pushViewController(vc, animated: true)
}
try this
let message = Message(sender: selfSender,messageId: messageId,sentDate: Date(),kind: .location(location))
DatabaseManager.shared.sendMessage(to: conversationId, otherUserEmail: strongSelf.otherUserEmail, name: name, newMessage: message, completion: { success in
if success {
print("sent location message")
}
else {
print("failed to send location message")
}
navigationController?.pushViewController(vc, animated: true)
})
}

How do you get a location capturer to run before an override segue?

So, I need to capture user's location (with their permission of course) before he gets to homepage. So on the login/register page I want to capture the location, but I need to do it before the override segue to homepage for logged in users. Any of you have any ideas? Below is the override segue.
I put location capturer before the segue in the override function, but it still went to homepage before the user had an opportunity to accept share location. This is not really unexpected since the entire override function is by definition an override function
override func viewDidAppear(_ animated: Bool) {
//////////////////////
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
let databaseRef = Database.database().reference()
guard let uid = Auth.auth().currentUser?.uid else { return }
guard let locValue: CLLocationCoordinate2D = manager.location?.coordinate else { return }
print("locations = \(locValue.latitude) \(locValue.longitude)")
latestLocation = ["latitude" : locValue.latitude, "longitude" : locValue.longitude]
let lat = locValue.latitude
let lon = locValue.longitude
dict = CLLocation(latitude: lat, longitude: lon)
print("dict", dict)
if let locationDictionary = latestLocation {
databaseRef.child("people").child(uid).child("Coordinates").setValue(locationDictionary)
}
}
//////////////////////
if Auth.auth().currentUser != nil {
self.performSegue(withIdentifier: "tohome", sender: nil)
}
}
Update: This is how I login and register.
#IBAction func RegisterPressed(_ sender: Any) {
Auth.auth().createUser(withEmail: (emailField.text ?? ""), password: (passwordField.text ?? "")) { (user, error) in
if let _eror = error {
//something bad happning
print(_eror.localizedDescription )
let alert = UIAlertController(title: "Error", message: "Invalid Entry or Duplicate.", preferredStyle: UIAlertController.Style.alert)
let action = UIAlertAction(title: "Ok", style: .default, handler: nil)
alert.addAction(action)
self.present(alert, animated: true, completion: nil)
}else{
//user registered successfully
print(user as Any)
if let userID = user?.user.uid
{
KeychainWrapper.standard.set((userID), forKey: "uid")
let databaseRef = Database.database().reference()
databaseRef.child("A1").child(userID).child("users").setValue(self.emailField.text!)
databaseRef.child("people").child(userID).child("postID").setValue(userID)
let components = self.emailField.text!.split(separator: "#")
let child1 = components[0] //will be jake
let child2 = components[1] //will be aol.com
print(components, child1, child2, "childs")
databaseRef.child("people").child(userID).child("e2").setValue(child2)
components.forEach { print($0) }
self.performSegue(withIdentifier: "tohome", sender: nil)
}
}
}
}
#IBAction func loginInPressed(_ sender: Any) {
Auth.auth().signIn(withEmail: (emailField.text ?? ""), password: (passwordField.text ?? "")) { (user, error) in
if let _eror = error {
//something bad happning
print(_eror.localizedDescription )
let alert = UIAlertController(title: "Error", message: "Incorrect Email or Password.", preferredStyle: UIAlertController.Style.alert)
let action = UIAlertAction(title: "Ok", style: .default, handler: nil)
alert.addAction(action)
self.present(alert, animated: true, completion: nil)
}else{
//user registered successfully
print(user as Any)
if let userID = user?.user.uid
{
KeychainWrapper.standard.set((userID), forKey: "uid")
self.performSegue(withIdentifier: "tohome", sender: nil) }
}
}
}
If I understand it correctly in viewDidAppear(_:) you have one condition. If it's true you immediately trying to perform the segue.
if Auth.auth().currentUser != nil {
self.performSegue(withIdentifier: "tohome", sender: nil)
}
As location is must to move into HomeScreen, why don't you do the navigation(segue) when you receive the first location update inside CLLocationManagerDelegate?
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
// check for existing location if we received earlier
guard self.latestLoc == nil else {
// we received one location earlier, navigation to Home completed. no need to proceed
// If we no longer need to listen for loc updates, we can stop listening further
manager.stopUpdatingLocation()
return
}
// ... Your exiting data base update code
guard let latestLoc = locations.last else { return }
self.latestLoc = latestLoc // If you want to pass this location to destination view controller in `prepare(for: UIStoryboardSegue, sender: Any?)`
// Also it will good practice to call manager.stopUpdatingLocation() if you need location only for once
// Now move to HomeScreen
self.performSegue(withIdentifier: "tohome", sender: nil)
// If we no longer need to listen for loc updates, we can stop listening further
manager.stopUpdatingLocation()
}

messageComposeViewController dismissing crash swift 3

On my App, I send alert via sms. I try to open a new view controller as a modal, and in this , the alert was sent.
But, when the sms is sent or when user click on the cancel button, the messageComposeViewController do not dismiss, and crash.
Error on xcode log is :
(lldb)
This is my code used to send alerts :
import UIKit
import CoreLocation
import Social
import MessageUI
import BRYXBanner
class AlertInProgressViewController: UIViewController, MFMessageComposeViewControllerDelegate, CLLocationManagerDelegate {
[... Code here ...]
func sms()
{
//Send sms
if(sms_exist()==true)
{
if( CLLocationManager.authorizationStatus() == CLAuthorizationStatus.authorizedWhenInUse || CLLocationManager.authorizationStatus() == CLAuthorizationStatus.authorizedAlways)
{
locationManager.delegate = self
locationManager.desiredAccuracy = kCLLocationAccuracyBest
locationManager.requestWhenInUseAuthorization()
locationManager.startUpdatingLocation()
locationManager.startUpdatingHeading()
let mlocation = self.locationManager.location
if mlocation != nil {
let latitude: Double = mlocation!.coordinate.latitude
let longitude: Double = mlocation!.coordinate.longitude
let latitude_convert:String = String(format:"%f", latitude)
let longitude_convert:String = String(format:"%f", longitude)
let location = number_street + " " + ville + "\nLatitude " + latitude_convert + " - Longitude : " + longitude_convert
let geoCoder = CLGeocoder()
let location_details = CLLocation(latitude: mlocation!.coordinate.latitude, longitude: mlocation!.coordinate.longitude)
geoCoder.reverseGeocodeLocation(location_details)
{
(placemarks, error) -> Void in
let placeArray = placemarks as [CLPlacemark]!
// Place details
var placeMark: CLPlacemark!
placeMark = placeArray?[0]
// Address dictionary
print(placeMark.addressDictionary)
// Location name
if let locationName = placeMark.addressDictionary?["Name"] as? NSString
{
print(locationName)
self.details_location = locationName as String
}
if let city = placeMark.addressDictionary?["City"] as? NSString
{
self.city = city as String
}
self.message = NSLocalizedString("IN_DANGER_TEXT_SHARE",comment:"I'm in danger, I'm currently at ") + location + "\n - " + self.details_location + " - " + self.city
let defaults = UserDefaults.standard
let sms_perso = defaults.object(forKey: "sms") as? String
if(MFMessageComposeViewController.canSendText()) {
let controller = MFMessageComposeViewController()
controller.body = self.message
controller.recipients = [sms_perso!]
controller.messageComposeDelegate = self
self.present(controller, animated: true, completion: nil)
}
else
{
print("Can't send sms")
}
}
}
}
}
}
[...]
func messageComposeViewController(_ controller: MFMessageComposeViewController, didFinishWith result: MessageComposeResult) {
//Original code but doesn't work too
//self.dismiss(animated: true, completion: nil)
OperationQueue.main.addOperation {
self.dismiss(animated: true, completion: {});
}
print("I want to dismiss here")
}
}
In xcode log, I can see : I want to dismiss here, so messageComposeViewController is called but after it's crash.
To display AlertInProgressViewController I use a storyboard segue.
I resolve my problem by changing this :
self.dismiss(animated: true, completion: {});
by
controller.dismiss(animated: true, completion: nil)
Yes, in Swift 4.x you must use
controller.dismiss(animated: true, completion: nil)
Here's a useful delegate function for MFMailComposeViewControllerDelegate
// MAIL COMPOSER DELEGATE
func mailComposeController(_ controller: MFMailComposeViewController, didFinishWith result: MFMailComposeResult, error: Error?) {
var resultMess = ""
switch result.rawValue {
case MFMailComposeResult.cancelled.rawValue:
resultMess = "Mail cancelled"
case MFMailComposeResult.saved.rawValue:
resultMess = "Mail saved"
case MFMailComposeResult.sent.rawValue:
resultMess = "Thanks for contacting us!\nWe'll get back to you asap."
case MFMailComposeResult.failed.rawValue:
resultMess = "Something went wrong with sending Mail, try again later."
default:break
}
// Show email result alert
let alert = UIAlertController(title: APP_NAME, message: resultMess, preferredStyle: .alert)
let ok = UIAlertAction(title: "OK", style: .default, handler: { (action) -> Void in
})
alert.addAction(ok)
present(alert, animated: true, completion: nil)
// Dismiss the controller
controller.dismiss(animated: true, completion: nil)
}

Swift 3.0 Allow Permission Alert Non-Stop

I want to get user location use CCLocationManager. I could get location clearly but "Allow location permission" alert showing repeatedly and non-stop when start first time on any device.
What should I do?
My AppDelegate.swift code;
class AppDelegate: UIResponder, UIApplicationDelegate, CLLocationManagerDelegate {
var window: UIWindow?
func applicationDidBecomeActive(_ application: UIApplication) {
let locationManager = CLLocationManager()
locationManager.requestAlwaysAuthorization()
locationManager.requestWhenInUseAuthorization()
if CLLocationManager.locationServicesEnabled() {
locationManager.delegate = self
locationManager.desiredAccuracy = kCLLocationAccuracyNearestTenMeters
locationManager.startUpdatingLocation()
if ((locationManager.location?.coordinate) != nil) {
let locValue:CLLocationCoordinate2D = (locationManager.location?.coordinate)!
let geoCoder = CLGeocoder()
let location = CLLocation(latitude: locValue.latitude, longitude: locValue.longitude)
geoCoder.reverseGeocodeLocation(location) {
(placemarks, error) -> Void in
let placeArray = placemarks as [CLPlacemark]!
// Place details
var placeMark: CLPlacemark!
placeMark = placeArray?[0]
if let state = placeMark.addressDictionary?["State"] as? NSString {
let parameters: Parameters = ["Location": state]
Alamofire.request(GlobalValues.APIUrl, method: .post, parameters: parameters).validate().responseJSON{
response in
if let result = response.result.value {
let JSON = result as! NSDictionary
let items = JSON.object(forKey: "Items") as! NSDictionary
userData.set(items.object(forKey: "fajr") as! String, forKey: "sabahNamazi")
userData.set(items.object(forKey: "dhuhr") as! String, forKey: "ogleNamazi")
userData.set(items.object(forKey: "asr") as! String, forKey: "ikindiNamazi")
userData.set(items.object(forKey: "maghrib") as! String, forKey: "aksamNamazi")
userData.set(items.object(forKey: "isha") as! String, forKey: "yatsiNamazi")
}
}
}
}
} else {
// create the alert
let alert = UIAlertController(title: "Konum Alınamıyor", message: "Telefonunuzun konum ayarlarını kontrol edip tekrar deneyin!", preferredStyle: UIAlertControllerStyle.alert)
// add the actions (buttons)
alert.addAction(UIAlertAction(title: "Tamam", style: UIAlertActionStyle.default, handler: nil))
// show the alert
self.window?.rootViewController?.present(alert, animated: true, completion: nil)
}
} else {
// create the alert
let alert = UIAlertController(title: "Konum Ayarını Açın", message: "Bu uygulama bulunduğunuz şehrin 'EZAN VAKİTLERİNİ' tespit edebilmek için konum bilginize ihtiyaç duyuyor.", preferredStyle: UIAlertControllerStyle.alert)
// add the actions (buttons)
alert.addAction(UIAlertAction(title: "Ayarlar", style: UIAlertActionStyle.default, handler: {(
action:UIAlertAction!) -> Void in
UIApplication.shared.openURL(URL(string: "prefs:root=LOCATION_SERVICES")!)
}))
alert.addAction(UIAlertAction(title: "İptal", style: UIAlertActionStyle.cancel, handler: nil))
// show the alert
self.window?.rootViewController?.present(alert, animated: true, completion: nil)
}
}
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
// Override point for customization after application launch.
return true
}
}
Alert Image:
put your location permission code in didFinishLaunchingWithOptions instead, so it will be asked once, then set any boolean value such as alreadyAskedPermission variable in NSDefault

CLLocationManager.authorizationStatus results in EXC_BAD_ACCESS code=2

My very first app is working fine so far, if location services are allowed for it.
As soon as I disable the location services for this app in particular (Airplane mode, as well as generally disabled location services are working as expected).
The code is the following:
func locationServices()->Bool{
if CLLocationManager.locationServicesEnabled() {
switch(CLLocationManager.authorizationStatus()) {
case .NotDetermined, .Restricted, .Denied:
return false
case .AuthorizedAlways, .AuthorizedWhenInUse:
return true
}
} else {
return false
}
}
Called from the viewDidLoad:
override func viewDidLoad() {
super.viewDidLoad()
txtNotes.delegate = self
datePicker.maximumDate = NSDate()
if (inc != nil) {
let Dateformatter = NSDateFormatter()
Dateformatter.dateStyle = NSDateFormatterStyle.MediumStyle
navigationItem.title = Dateformatter.stringFromDate((inc?.date)!)
datePicker.date = (inc?.date)!
txtNotes.text = inc?.notes
ratingControl.rating = (inc?.rating)!
lblAccuracy.text = inc?.geoloc
self.location = inc?.geocor
}
else {
if(locationServices()){
self.locationManager = CLLocationManager()
locationManager!.delegate = self
locationManager!.requestWhenInUseAuthorization()
locationManager!.desiredAccuracy = kCLLocationAccuracyBest
locationManager!.startUpdatingLocation()
}
else{
lblAccuracy.text = "Location Services Disabled"
let alertController = UIAlertController(
title: "Location Services Disabled",
message: "Please allow this application to use location services",
preferredStyle: .Alert)
let cancelAction = UIAlertAction(title: "Cancel", style: .Cancel, handler: nil)
alertController.addAction(cancelAction)
let openAction = UIAlertAction(title: "Open Settings", style: .Default) { (action) in
if let url = NSURL(string:UIApplicationOpenSettingsURLString) {
UIApplication.sharedApplication().openURL(url)
}
}
alertController.addAction(openAction)
self.presentViewController(alertController, animated: true, completion: nil)
viewDidLoad()
}
}
}
Accessing a not yet initialized delegate is not a smart idea...
Initializing prior to accessing it resolved my issue.

Resources