UIAlert shows two times in iOS Swift? - ios

I have been trying to show an alert for internet connection is available or not. Implemented code for checking the internet and it works fine. But, when the internet is not readable, I am trying to show alert but alert show twice.
here is the code tried:
#objc func reachabilityChanged(_ note: NSNotification) {
let reachability = note.object as! Reachability
if reachability.connection != .unavailable {
if reachability.connection == .wifi {
print("Reachable via WiFi")
} else {
print("Reachable via Cellular")
}
} else {
print("Not reachable")
let alert = UIAlertController(title: "No Internet Connection", message: "Make sure your device is connected to the internet.", preferredStyle: UIAlertController.Style.alert)
alert.addAction(UIAlertAction(title: "OK", style: UIAlertAction.Style.default, handler: nil))
// self.window?.rootViewController?.present(alert, animated: true, completion: nil)
topMostViewController().present(alert, animated: true, completion: nil)
// let alertVC = UIAlertController(title: "No Internet Connection" , message: "Make sure your device is connected to the internet.", preferredStyle: UIAlertController.Style.alert)
// let okAction = UIAlertAction(title: "Okay", style: UIAlertAction.Style.cancel) { (alert) in
//// exit(0) // Your code here
// }
// alertVC.addAction(okAction)
// DispatchQueue.main.async {
// var presentVC = self.window?.rootViewController
// while let next = presentVC?.presentedViewController {
// presentVC = next
// }
// presentVC?.present(alertVC, animated: true, completion: nil)
// }
}
}
func topMostViewController() -> UIViewController {
var topViewController: UIViewController? = UIApplication.shared.keyWindow?.rootViewController
while ((topViewController?.presentedViewController) != nil) {
topViewController = topViewController?.presentedViewController
}
return topViewController!
}

Related

Internet Reconnection Swift

My app currently shows an alert if there isn't an internet connection. However, I would like it to reconnect automatically once internet connection is detected without user needing to restart the app.
the code for I used currently is
if Reachability.isConnectedToNetwork() == true {
print("Internet Connection Available!")
} else {
let alertController = UIAlertController(title: "Alert",
message: "Internet Connection not Available!",
preferredStyle: UIAlertControllerStyle.alert)
alertController.addAction(UIAlertAction(title: "Dismiss", style: UIAlertActionStyle.default,handler: nil))
self.present(alertController, animated: true, completion: nil)
}
anyone can give some advice? if my question isn't clear, do let me know. Thx guys!
You should addObserver of Reachability in applicationDidFinishLaunching method, like below,
NotificationCenter.default.addObserver(self, selector: #selector(networkStatusChanged(_:)), name: NSNotification.Name(rawValue: ReachabilityStatusChangedNotification), object: nil)
Reach().monitorReachabilityChanges()
Implement this method as well,
#objc func networkStatusChanged(_ notification: Notification) {
let userInfo = (notification as NSNotification).userInfo
if let status = userInfo?["Status"] as? String, status == "Offline" {
//Display alert view
} else if let status = userInfo?["Status"] as? String, status != "Unknown" {
//Internet connection is active
}
}
Above function automatically triggers call when there is active internet connection.
It's Working well for me
func myconn(){
if Reachability.isConnectedToNetwork() == true
{
print("Internet Connection Available!")
}
else
{
let alertController = UIAlertController(title: "Alert", message:
"Internet Connection not Available!", preferredStyle: UIAlertControllerStyle.alert)
alertController.addAction(UIAlertAction(title: "Dismiss", style: UIAlertActionStyle.default,handler: nil))
self.present(alertController, animated: true, completion: nil)
DispatchQueue.main.asyncAfter(deadline: .now() + 10.0, execute: {
self.myconn()
})
}
}
You need to add addObserver of ReachabilityChangedNotification.
NSNotificationCenter.defaultCenter().addObserver(self, selector:"checkForReachability:", name: ReachabilityChangedNotification, object: nil);
self.reachability = Reachability.reachabilityForInternetConnection();
self.reachability.startNotifier();
func checkForReachability(notification:NSNotification)
{
let networkReachability = notification.object as Reachability;
var remoteHostStatus = networkReachability.currentReachabilityStatus()
if (remoteHostStatus.value == NotReachable.value)
{
print("Not Reachable")
}
else if (remoteHostStatus.value == ReachableViaWiFi.value)
{
print("Reachable via Wifi")
}
else
{
print("Reachable")
}
}
Whenever change the network it will notify you.
You could also use RxSwift to observe you reachability notifications and deal with the changes whenever you get a new connection state.
like this:
var isOnline: Bool {
guard let reachability = reachability else { return false }
return reachability.currentReachabilityStatus.isOnline
}
func connectionStatus() -> Observable<ConnectionStatus> {
return notificationCenter
.rx
.notification(ReachabilityChangedNotification)
.observeOn(observeScheduler)
.flatMap { notification -> Observable<ConnectionStatus> in
guard let reachability = notification.object as? Reachability else {
return .empty()
}
return .just(ConnectionStatus(isOnline: reachability.isReachable))
}
.startWith(ConnectionStatus(isOnline: isOnline))
.distinctUntilChanged()
}
This way you'll be observing any changes in the connection and can react to it the you you want.
You just need to Subscribe to the Observable<ConnectionStatus> and then you can decide if you want the user to trigger a new reconnection flow or if you would retry a few times before displaying it.

When I try to send a text message through my app the Messages screen is automatically cancelled

I am tying to have my app take a users input to format a text message so that they can connect to an external device in the proper format through text. I have the initial setup text message working but if the user wishes to delete the geo-fence (the initial text message is responsible for setting it) they need to send a different text message however the Messages screen is automatically cancelled when called.
#IBAction func addGeoFencePushed(_ sender: Any) {
if(!geoFenceIsEnabled()){
let alertController = UIAlertController(title: nil, message: "How large would you like the geofence to be?", preferredStyle: .alert)
let confirmAction = UIAlertAction(title: "Confirm", style: .default) { (_) in
if let field = alertController.textFields?[0] {
// store your data
ALGlobal.sharedInstance.globalDefaults.set(field.text! as String, forKey: "geoFenceSize")
let rad = Double(field.text!)
ALGlobal.sharedInstance.geoFenceRadius = rad!
self.buttonSetting = 1
self.toggleButton()
self.drawGeoFence(radius: rad!)
self.turnOnFenceText(radius: Int(rad!))
} else {
// user did not fill field
}
}
let cancelAction = UIAlertAction(title: "Cancel", style: .cancel) { (_) in }
alertController.addTextField { (textField) in
textField.placeholder = "Feet"
textField.keyboardType = .numberPad
}
alertController.addAction(confirmAction)
alertController.addAction(cancelAction)
self.present(alertController, animated: true, completion: nil)
}
else{
// create the alert
let alert = UIAlertController(title: "Confirm", message: "Are you sure you want to remove the geo-fence?", preferredStyle: UIAlertControllerStyle.alert)
let confirmAction = UIAlertAction(title: "Confirm", style: .default) { (_) in
alert.dismiss(animated: true, completion: nil)
self.removeGeoFence()
}
alert.addAction(confirmAction)
alert.addAction(UIAlertAction(title: "Cancel", style: .cancel, handler: nil))
// show the alert
self.present(alert, animated: true, completion: nil)
}
}
This is what is responsible for determining which text message to display.
func removeGeoFence(){
self.turnOffFenceText()
ALGlobal.sharedInstance.globalDefaults.removeObject(forKey: "geoFenceSize")
ALGlobal.sharedInstance.geoFenceRadius = 0
self.buttonSetting = 0
self.toggleButton()
self.clearMap()
}
func turnOnFenceText(radius: Int){
let radiusConverted = Int(radius / 3)
messageVC.body = "G1,1,0,\(radiusConverted)M"
messageVC.recipients = [ALGlobal.sharedInstance.globalDefaults.object(forKey: "devicePhoneNumber") as! String]
self.present(messageVC, animated: true, completion: nil)
}
func turnOffFenceText(){
messageVC.body = "G1,0"
messageVC.recipients = [ALGlobal.sharedInstance.globalDefaults.object(forKey: "devicePhoneNumber") as! String]
self.present(messageVC, animated: true, completion: nil)
}
func messageComposeViewController(_ controller: MFMessageComposeViewController, didFinishWith result: MessageComposeResult) {
switch (result.rawValue) {
case MessageComposeResult.cancelled.rawValue:
print("Message was cancelled")
messageVC.dismiss(animated: true, completion: nil)
case MessageComposeResult.failed.rawValue:
print("Message failed")
messageVC.dismiss(animated: true, completion: nil)
case MessageComposeResult.sent.rawValue:
print("Message was sent")
messageVC.dismiss(animated: true, completion: nil)
//self.dismiss(animated: true, completion: nil)
default:
break;
}
}
And these are the message controllers. When removeGeoFence() is called the console prints out "Message was cancelled" and the Messages app never opens and I can't figure out why.
You need to recreate the messageVC after you dismiss it otherwise your trying to reopen a dismissed view and that results in a black screen so in the turnOnFenceText() and turnOffFenceText() I reinitialized the messageVC:
func turnOnFenceText(radius: Int){
messageVC = MFMessageComposeViewController()
messageVC.messageComposeDelegate = self;
let radiusConverted = Int(radius / 3)
messageVC.body = "G1,1,0,\(radiusConverted)M"
messageVC.recipients = [ALGlobal.sharedInstance.globalDefaults.object(forKey: "devicePhoneNumber") as! String]
self.present(messageVC, animated: true, completion: nil)
}
func turnOffFenceText(){
messageVC = MFMessageComposeViewController()
messageVC.messageComposeDelegate = self;
messageVC.body = "G1,0"
messageVC.recipients = [ALGlobal.sharedInstance.globalDefaults.object(forKey: "devicePhoneNumber") as! String]
self.present(messageVC, animated: true, completion: nil)
}
That fixed the problem

Adding Activity Indicator after Clicking "LOGIN"?

I would like to add an Activity Indicator for my Login VC so that users will see that spinner thing once they click the "login" button. I have done multiple attempts and failed. Even if I put in codes for hiding the activity indicator, it just keeps animating even before clicking the "login" button. I deleted those codes, and have my original codes below (without activity indicator).
import UIKit
import Firebase
class LoginViewController: UIViewController {
var imageView: UIImageView!
override func viewDidLoad() {
super.viewDidLoad()
imageView = UIImageView(frame: view.bounds)
imageView.contentMode = .scaleAspectFill
imageView.clipsToBounds = true
imageView.image = #imageLiteral(resourceName: "background")
imageView.center = view.center
view.addSubview(imageView)
self.view.sendSubview(toBack: imageView)
}
//Outlets
#IBOutlet weak var emailTextField: UITextField!
#IBOutlet weak var passwordTextField: UITextField!
//Login Action
#IBAction func loginAction(_ sender: AnyObject) {
if self.emailTextField.text == "" || self.passwordTextField.text == "" {
//Alert to tell the user that there was an error because they didn't fill anything in the textfields because they didn't fill anything in
let alertController = UIAlertController(title: "Error", message: "Please enter an email and password.", preferredStyle: .alert)
let defaultAction = UIAlertAction(title: "OK", style: .cancel, handler: nil)
alertController.addAction(defaultAction)
self.present(alertController, animated: true, completion: nil)
} else {
Auth.auth().signIn(withEmail: self.emailTextField.text!, password: self.passwordTextField.text!) { (user, error) in
if error == nil {
//Print into the console if successfully logged in
print("You have successfully logged in")
//Go to the HomeViewController if the login is sucessful
let vc = self.storyboard?.instantiateViewController(withIdentifier: "Home")
self.present(vc!, animated: true, completion: nil)
} else {
//Tells the user that there is an error and then gets firebase to tell them the error
let alertController = UIAlertController(title: "Error", message: error?.localizedDescription, preferredStyle: .alert)
let defaultAction = UIAlertAction(title: "OK", style: .cancel, handler: nil)
alertController.addAction(defaultAction)
self.present(alertController, animated: true, completion: nil)
}
}
}
}
so I know the first step is probably dragging the activity indicator to the VC in Storyboard, but what's next?
You need to create a IBOutlet of dragged UIActivityIndicator. Then in viewDidLoadfunc hide this UIActivityIndicator with it's IBOutlet. When you click on Login Button, then unhide this activityIndicator and hide again, once receive response from login.
Create an IBOUtlet of your activity indicator from Storyboard to your Viewcontroller -
You can then in your ViewDidLoad or your storyboard set the below property
activityIndicator.hidesWhenStopped = true;
And when you want to start it, call
activityIndicator.startAnimating();
And to stop it from animating -
activityIndicator.stopAnimating();
The same way you created your IBOutlets of UITextField, create one with your UIActivityIndicator. Make sure your indicator's hidesWhenStopped is set to true in the storyboard.
Then animate it before calling your signin method, and stop it on the completion handler
#IBOutlet weak var activityIndicator: UIActivityIndicator!
//...
activityIndicator.startAnimating()
Auth.auth().signIn(withEmail: self.emailTextField.text!, password: self.passwordTextField.text!) { (user, error) in {
activityIndicator.stopAnimating()
//...
}
You can create UIActivityIndicatorView in your class programmatically & customize it in viewDidLoad
var activityIndicator = UIActivityIndicatorView(activityIndicatorStyle: UIActivityIndicatorViewStyle.Gray)
// Add below code in viewDidLoad
self.activityIndicator.hidesWhenStopped = true
self.activityIndicator.center = view.center
self.view.addSubView(self.activityIndicator)
Now do start & stop animating whereever you need
//Login Action
#IBAction func loginAction(_ sender: AnyObject) {
self.activityIndicator.startAnimating()
if self.emailTextField.text == "" || self.passwordTextField.text == "" {
//Alert to tell the user that there was an error because they didn't fill anything in the textfields because they didn't fill anything in
let alertController = UIAlertController(title: "Error", message: "Please enter an email and password.", preferredStyle: .alert)
let defaultAction = UIAlertAction(title: "OK", style: .cancel, handler: nil)
alertController.addAction(defaultAction)
self.present(alertController, animated: true, completion: nil)
} else {
Auth.auth().signIn(withEmail: self.emailTextField.text!, password: self.passwordTextField.text!) { (user, error) in
self.activityIndicator.stopAnimating()
if error == nil {
//Print into the console if successfully logged in
print("You have successfully logged in")
//Go to the HomeViewController if the login is sucessful
let vc = self.storyboard?.instantiateViewController(withIdentifier: "Home")
self.present(vc!, animated: true, completion: nil)
} else {
//Tells the user that there is an error and then gets firebase to tell them the error
let alertController = UIAlertController(title: "Error", message: error?.localizedDescription, preferredStyle: .alert)
let defaultAction = UIAlertAction(title: "OK", style: .cancel, handler: nil)
alertController.addAction(defaultAction)
self.present(alertController, animated: true, completion: nil)
}
}
}
In your storyboard, you can find checkbox.
startsAnimating
HidesWhenStops(check this in your storyboard.)
#IBOutlet weak var activityIndicator: UIActivityIndicator!
#IBAction func loginAction(_ sender: AnyObject) {
activityIndicator.startAnimating()
if self.emailTextField.text == "" || self.passwordTextField.text == "" {
//Alert to tell the user that there was an error because they didn't fill anything in the textfields because they didn't fill anything in
let alertController = UIAlertController(title: "Error", message: "Please enter an email and password.", preferredStyle: .alert)
activityIndicator.stopAnimating()
let defaultAction = UIAlertAction(title: "OK", style: .cancel, handler: nil)
alertController.addAction(defaultAction)
self.present(alertController, animated: true, completion: nil)
} else {
Auth.auth().signIn(withEmail: self.emailTextField.text!, password: self.passwordTextField.text!) { (user, error) in
if error == nil {
//Print into the console if successfully logged in
print("You have successfully logged in")
activityIndicator.stopAnimating()
//Go to the HomeViewController if the login is sucessful
let vc = self.storyboard?.instantiateViewController(withIdentifier: "Home")
self.present(vc!, animated: true, completion: nil)
} else {
//Tells the user that there is an error and then gets firebase to tell them the error
let alertController = UIAlertController(title: "Error", message: error?.localizedDescription, preferredStyle: .alert)
let defaultAction = UIAlertAction(title: "OK", style: .cancel, handler: nil)
alertController.addAction(defaultAction)
self.present(alertController, animated: true, completion: nil)
}
}
}
}
An alternative Approach. Adding the UIActivityViewController programatically:
In the LoginViewController class add
let myActivityIndicator = UIActivityIndicatorView(activityIndicatorStyle: UIActivityIndicatorViewStyle.gray)
In the viewDidLoad() add the following
myActivityIndicator.hidesWhenStopped = true
myActivityIndicator.center = view.center
view.addSubview(myActivityIndicator)
In #IBAction func loginAction(_ sender: AnyObject) in the else part
add
activityIndicator.startAnimating()
Auth.auth().signIn(withEmail: self.emailTextField.text!, password: self.passwordTextField.text!) { (user, error) in {
activityIndicator.stopAnimating()
I have written a class to use progress hud properly. You just need to drag and drop the class to your project...
https://github.com/emraz/ERProgressHud
For showing progress hud write ..
ERProgressHud.show()
For hiding progress hud write ..
ERProgressHud.hide()
In your code ..
//Login Action
#IBAction func loginAction(_ sender: AnyObject) {
if self.emailTextField.text == "" || self.passwordTextField.text == "" {
//Alert to tell the user that there was an error because they didn't fill anything in the textfields because they didn't fill anything in
let alertController = UIAlertController(title: "Error", message: "Please enter an email and password.", preferredStyle: .alert)
let defaultAction = UIAlertAction(title: "OK", style: .cancel, handler: nil)
alertController.addAction(defaultAction)
self.present(alertController, animated: true, completion: nil)
return
}
else {
ERProgressHud.show()
Auth.auth().signIn(withEmail: self.emailTextField.text!, password: self.passwordTextField.text!) { (user, error) in
ERProgressHud.hide()
if error == nil {
//Print into the console if successfully logged in
print("You have successfully logged in")
//Go to the HomeViewController if the login is sucessful
let vc = self.storyboard?.instantiateViewController(withIdentifier: "Home")
self.present(vc!, animated: true, completion: nil)
} else {
//Tells the user that there is an error and then gets firebase to tell them the error
let alertController = UIAlertController(title: "Error", message: error?.localizedDescription, preferredStyle: .alert)
let defaultAction = UIAlertAction(title: "OK", style: .cancel, handler: nil)
alertController.addAction(defaultAction)
self.present(alertController, animated: true, completion: nil)
}
}
}
}

running iOS 10.0 on Wi-Fi connected to an IPv6 network

Iphone app rejected because of the the reason that
“We discovered one or more bugs in your app when reviewed on iPad and iPhone running iOS 10.0 on Wi-Fi connected to an IPv6 network.”
Anyone can help to solve it?
import UIKit
let useClosures = false
class ViewController: UIViewController {
let reachability = Reachability.reachabilityForInternetConnection()
#IBOutlet weak var WebView: UIWebView!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
view.backgroundColor = UIColor.redColor()
let URL = NSURL(string: "https://gph-shop.com/tracing")
WebView.loadRequest(NSURLRequest(URL: URL!))
if (useClosures) {
reachability?.whenReachable = { reachability in
print("Reachable")
}
reachability?.whenUnreachable = { reachability in
print("Unreachable")
}
} else {
NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(ViewController.reachabilityChanged(_:)), name: ReachabilityChangedNotification, object: reachability)
}
reachability?.startNotifier()
// Initial reachability check when the app starts
if let reachability = reachability {
dispatch_async(dispatch_get_main_queue()) {
if reachability.isReachable() {
let alertController = UIAlertController(title: "", message: "wi-fi connected", preferredStyle: .Alert)
let defaultAction = UIAlertAction(title: "OK", style: .Default, handler: nil)
alertController.addAction(defaultAction)
self.presentViewController(alertController, animated: true, completion: nil)
} else {
let alertController = UIAlertController(title: "Alert", message: "Please connect to internet", preferredStyle: .Alert)
let defaultAction = UIAlertAction(title: "OK", style: .Default, handler: nil)
alertController.addAction(defaultAction)
self.presentViewController(alertController, animated: true, completion: nil)
}
}
}
}
deinit {
reachability?.stopNotifier()
if (!useClosures) {
NSNotificationCenter.defaultCenter().removeObserver(self, name: ReachabilityChangedNotification, object: nil)
}
}
func reachabilityChanged(note: NSNotification) {
let reachability = note.object as! Reachability
// Initial reachability check while surfing in the app
if reachability.isReachable() {
let alertController = UIAlertController(title: "Alert", message: "Reachable", preferredStyle: .Alert)
let defaultAction = UIAlertAction(title: "OK", style: .Default, handler: nil)
alertController.addAction(defaultAction)
self.presentViewController(alertController, animated: true, completion: nil)
} else {
let alertController = UIAlertController(title: "Alert", message: "Please connect to internet", preferredStyle: .Alert)
let defaultAction = UIAlertAction(title: "OK", style: .Default, handler: nil)
alertController.addAction(defaultAction)
self.presentViewController(alertController, animated: true, completion: nil)
}
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
You need to debug your app in a NAT64 Network.
(You can create it by using your macOS.)
And Apple support article is following:
https://developer.apple.com/library/content/documentation/NetworkingInternetWeb/Conceptual/NetworkingOverview/UnderstandingandPreparingfortheIPv6Transition/UnderstandingandPreparingfortheIPv6Transition.html

How to access the view controller which is evoked by the stopRecording() method of ReplayKit framework. And how to save the video in my camera roll

How to access the view controller which is evoked by the stopRecording() method of ReplayKit framework. And how to save the video in the camera roll?
Try this if you haven't gotten to work yet:
func stopRecording() {
let sharedRecorder = RPScreenRecorder.sharedRecorder()
sharedRecorder.stopRecordingWithHandler { (previewViewController: RPPreviewViewController?, error: NSError?) in
if previewViewController != nil {
print("stopped recording")
previewViewController!.previewControllerDelegate = self
let alertController = UIAlertController(title: "Recording", message: "Tap view to watch, edit, share, or save your screen recording!", preferredStyle: .Alert)
let viewAction = UIAlertAction(title: "View", style: .Default, handler: { (action: UIAlertAction) -> Void in
self.view?.window?.rootViewController?.presentViewController(previewViewController!, animated: true, completion: nil)
})
alertController.addAction(viewAction)
self.previewViewController = previewViewController!
self.previewViewController.modalPresentationStyle = UIModalPresentationStyle.FullScreen
self.view?.window?.rootViewController!.presentViewController(alertController, animated: true, completion: nil)
} else {
print("recording stopped working")
//create the alert
let alert = UIAlertController(title: "Alert", message: "Sorry, there was an error recording your screen. Please Try Again!", preferredStyle: UIAlertControllerStyle.Alert)
// show the alert
self.view!.window?.rootViewController!.presentViewController(alert, animated: true, completion: nil)
alert.addAction(UIAlertAction(title: "Try Again!", style: UIAlertActionStyle.Destructive, handler: { action in
// add action
}))
}
}
}
internal func previewControllerDidFinish(previewController: RPPreviewViewController) {
self.previewViewController.dismissViewControllerAnimated(true, completion: nil)
print("cancel and save button pressed")
}

Resources