I'm making an app that should load all the gas stations and their prices on the state.
The map should reload the prices if the user selects a diferent type of gas (Magna, Premium and Diesel). This is made through a UISegment control.
The trouble is that when I reload the map it doesn't print the correct price (the default one is magna, and when I select the other type of gas it doesn't load the new prices).
This is my code.
class MapViewController: UIViewController,MKMapViewDelegate, CLLocationManagerDelegate,UICollectionViewDelegate, UICollectionViewDataSource {
let manager = CLLocationManager()
public let sMAGNA = "magna"
public let sPREMIUM = "premium"
public let sDIESEL = "diesel"
public let MIN_TIME: CLong = 400
private let MIN_DISTANCE: Float = 1000
private var ubicaciones_selected: [Ubicacion] = []
private var ubicaciones_magna: [Ubicacion] = []
private var ubicaciones_premium: [Ubicacion] = []
private var ubicaciones_diesel: [Ubicacion] = []
private let REQUEST_LOCATION = 1
private var latlon: String = ""
private var mType: String = "magna"
var ubicaciones:[Ubicacion] = []
var Ubigaspin = MKPointAnnotation()
#IBAction func MapType(_ sender: Any) {
if mapa.mapType == MKMapType.standard{
mapa.mapType = MKMapType.satellite
} else {
mapa.mapType = MKMapType.standard
}
}
override func viewDidLoad() {
super.viewDidLoad()
self.mapa.delegate = self
//con esto obtendremos la ubicacion del usuario
manager.delegate = self
manager.desiredAccuracy = kCLLocationAccuracyBest
manager.requestWhenInUseAuthorization()
mapa.showsUserLocation = true
manager.startUpdatingLocation()
//se cargan los pines y las gasolinas
loadGas(tipo: mType)
}
func loadGas(tipo:String){
mType = tipo
var ubicaciones:[Ubicacion] = []
switch tipo {
case sMAGNA:
ubicaciones = ubicaciones_magna
case sPREMIUM:
ubicaciones = ubicaciones_premium
case sDIESEL:
ubicaciones = ubicaciones_diesel
default:
ubicaciones = ubicaciones_magna
}
if ubicaciones.count == 0 {
let url = URL(string: "http://192.241.214.56/api/"+tipo+"/?format=json")
URLSession.shared.dataTask(with: url!, completionHandler: {
(data, response, error) in
if(error != nil){
print("error")
}else{
do{
let ubicaciones_json = try JSONSerialization.jsonObject(with: data!, options:.allowFragments) as! [[String : AnyObject]]
for ubicacion in ubicaciones_json{
let nombre:String = ubicacion["nombre"] as! String
let direccion:String = ubicacion["direccion"] as! String
let precio_magna:Float = ubicacion["precio_magna"] as! Float
let precio_premium:Float = ubicacion["precio_premium"] as! Float
let precio_diesel:Float = ubicacion["precio_diesel"] as! Float
let ubicacion:String = ubicacion["ubicacion"] as! String
let p = Ubicacion()
p.ubicacion = ubicacion
p.setLatLng()
p.nombre = nombre
p.direccion = direccion
p.precio_magna = precio_magna
p.precio_premium = precio_premium
p.precio_diesel = precio_diesel
ubicaciones.append(p)
}
self.ubicaciones = ubicaciones
OperationQueue.main.addOperation({
self.updatePins(ubicaciones: ubicaciones)
})
}catch let error as NSError{
print(error)
}
}
}).resume()
}else{
self.ubicaciones = ubicaciones
self.updatePins(ubicaciones: ubicaciones)
}
}
func updatePins(ubicaciones:[Ubicacion]){
mapa.removeAnnotations(mapa.annotations)
for ubicacion in ubicaciones{
let anno = CustonAnno(ubicacion:ubicacion, image: #imageLiteral(resourceName: "icon"))
anno.coordinate = CLLocationCoordinate2D(latitude: ubicacion.latitude!, longitude: ubicacion.longitude!)
anno.title=ubicacion.nombre
//anno.subtitle="$\(ubicacion.getPrecio(tipo: mType))"
self.mapa.addAnnotation(anno)
}
}
#IBAction func changeSegment(_ sender: UISegmentedControl) {
print(sender.selectedSegmentIndex)
switch sender.selectedSegmentIndex {
case 0:
loadGas(tipo: sMAGNA)
case 1:
loadGas(tipo: sPREMIUM)
case 2:
loadGas(tipo: sDIESEL)
default:
loadGas(tipo: sMAGNA)
}
}
}
I think your problem is with your ubicaciones vars, you have a local var and a instance var with the same name, you need work all the time with your instance var instead of create another, you are also losing your information over and over again making your network calls needed every time you change your gas type
Try replacing your loadGas method
by this one
func loadGas(tipo:String){
mType = tipo
switch tipo {
case sMAGNA:
if(ubicaciones_magna.count > 0){
self.ubicaciones = ubicaciones_magna
self.updatePins(ubicaciones: self.ubicaciones)
return
}
case sPREMIUM:
if(ubicaciones_premium.count > 0){
self.ubicaciones = ubicaciones_premium
self.updatePins(ubicaciones: self.ubicaciones)
return
}
case sDIESEL:
if(ubicaciones_diesel.count > 0){
self.ubicaciones = ubicaciones_diesel
self.updatePins(ubicaciones: self.ubicaciones)
return
}
default:
if(ubicaciones_magna.count > 0){
self.ubicaciones = ubicaciones_magna
self.updatePins(ubicaciones: self.ubicaciones)
return
}
}
let url = URL(string: "http://192.241.214.56/api/"+tipo+"/?format=json")
URLSession.shared.dataTask(with: url!, completionHandler: {
(data, response, error) in
if(error != nil){
print("error")
}else{
do{
let ubicaciones_json = try JSONSerialization.jsonObject(with: data!, options:.allowFragments) as! [[String : AnyObject]]
var newUbications:[Ubicacion] = []
for ubicacion in ubicaciones_json{
let nombre:String = ubicacion["nombre"] as! String
let direccion:String = ubicacion["direccion"] as! String
let precio_magna:Float = ubicacion["precio_magna"] as! Float
let precio_premium:Float = ubicacion["precio_premium"] as! Float
let precio_diesel:Float = ubicacion["precio_diesel"] as! Float
let ubicacion:String = ubicacion["ubicacion"] as! String
let p = Ubicacion()
p.ubicacion = ubicacion
p.setLatLng()
p.nombre = nombre
p.direccion = direccion
p.precio_magna = precio_magna
p.precio_premium = precio_premium
p.precio_diesel = precio_diesel
newUbications.append(p)
}
switch tipo {
case sMAGNA:
self.ubicaciones_magna = newUbications
self.ubicaciones = self.ubicaciones_magna
case sPREMIUM:
self.ubicaciones_premium = newUbications
self.ubicaciones = self.ubicaciones_premium
case sDIESEL:
self.ubicaciones_diesel = newUbications
self.ubicaciones = ubicaciones_diesel
default:
self.ubicaciones_magna = newUbications
self.ubicaciones = self.ubicaciones_magna
}
OperationQueue.main.addOperation({
self.updatePins(ubicaciones: self.ubicaciones)
})
}catch let error as NSError{
print(error)
}
}
}).resume()
}
Related
There are users being downloaded from firebase and displayed on a UITableView where the cells are selectable and once selected will have a check mark. So from firebase is it is asynchronously downloaded so I think this could be the start of me solving the problem but not sure. When selecting lets say two cells when the view appears and then you begin scrolling through the list other cells will appear to be selected when the user did not select them. Below will be code and pictures of the occurrence.
Firebase Call
func getTableViewData() {
Database.database().reference().child("Businesses").queryOrdered(byChild: "businessName").observe(.childAdded, with: { (snapshot) in
let key = snapshot.key
if(key == self.loggedInUser?.uid) {
print("Same as logged in user, so don't show!")
} else {
if let locationValue = snapshot.value as? [String: AnyObject] {
let lat = Double(locationValue["businessLatitude"] as! String)
let long = Double(locationValue["businessLongitude"] as! String)
let businessLocation = CLLocation(latitude: lat!, longitude: long!)
let latitude = self.locationManager.location?.coordinate.latitude
let longitude = self.locationManager.location?.coordinate.longitude
let userLocation = CLLocation(latitude: latitude!, longitude: longitude!)
let distanceInMeters: Double = userLocation.distance(from: businessLocation)
let distanceInMiles: Double = distanceInMeters * 0.00062137
let distanceLabelText = String(format: "%.2f miles away", distanceInMiles)
var singleChildDictionary = locationValue
singleChildDictionary["distanceLabelText"] = distanceLabelText as AnyObject
singleChildDictionary["distanceInMiles"] = distanceInMiles as AnyObject
self.usersArray.append(singleChildDictionary as NSDictionary)
self.usersArray = self.usersArray.sorted {
!($0?["distanceInMiles"] as! Double > $1?["distanceInMiles"] as! Double)
}
}
//insert the rows
//self.followUsersTableView.insertRows(at: [IndexPath(row:self.usersArray.count-1,section:0)], with: UITableViewRowAnimation.automatic)
self.listedBusiness.reloadData()
}
}) { (error) in
print(error.localizedDescription)
}
}
TableView Setup
// MARK: - Table view data source
override func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if searchController.isActive && searchController.searchBar.text != ""{
return filteredUsers.count
}
return self.usersArray.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath) as! CustomerAddSelectedBusinessesCell
var user : NSDictionary?
if searchController.isActive && searchController.searchBar.text != ""{
user = filteredUsers[indexPath.row]
} else {
user = self.usersArray[indexPath.row]
}
if cell.isSelected == true {
var user = self.usersArray[indexPath.row]
if CLLocationManager.locationServicesEnabled() {
switch(CLLocationManager.authorizationStatus()) {
case .notDetermined, .restricted, .denied:
print("No access")
cell.businessName.text = String(user?["businessName"] as! String)
cell.businessStreet.text = String(user?["businessStreet"] as! String)
cell.businessCity.text = String(user?["businessCity"] as! String)
//cell.selectedCell.image = UIImage(named: "cellSelected")
let businessProfilePicture = String(user?["profPicString"] as! String)
if (businessProfilePicture.count) > 0 {
let url = URL(string: (businessProfilePicture))
DispatchQueue.global().async {
let data = try? Data(contentsOf: url!)
DispatchQueue.main.async {
let image = UIImage(data: data!)?.potter_circle
cell.businessImage.contentMode = UIView.ContentMode.scaleAspectFill
cell.businessImage.image = image
}
}
} else {
let image = UIImage(named: "default")?.potter_circle
cell.businessImage.contentMode = UIView.ContentMode.scaleAspectFill
cell.businessImage.image = image
}
//cell.profileImage.image =
//cell.businessDistance.text = String(user?["distanceLabelText"] as! String)
case .authorizedAlways, .authorizedWhenInUse:
print("Access")
print("****Called")
cell.businessName.text = String(user?["businessName"] as! String)
cell.businessStreet.text = String(user?["businessStreet"] as! String)
cell.businessCity.text = String(user?["businessCity"] as! String)
cell.businessDistance.text = String(user?["distanceLabelText"] as! String)
//cell.selectedCell.image = UIImage(named: "cellSelected")
let businessProfilePicture = String(user?["profPicString"] as! String)
if (businessProfilePicture.count) > 0 {
let url = URL(string: (businessProfilePicture))
DispatchQueue.global().async {
let data = try? Data(contentsOf: url!)
DispatchQueue.main.async {
let image = UIImage(data: data!)?.potter_circle
cell.businessImage.contentMode = UIView.ContentMode.scaleAspectFill
cell.businessImage.image = image
}
}
} else {
let image = UIImage(named: "default")?.potter_circle
cell.businessImage.contentMode = UIView.ContentMode.scaleAspectFill
cell.businessImage.image = image
}
}
} else {
print("Location services are not enabled")
}
} else if cell.isSelected == false {
var user = self.usersArray[indexPath.row]
if CLLocationManager.locationServicesEnabled() {
switch(CLLocationManager.authorizationStatus()) {
case .notDetermined, .restricted, .denied:
print("No access")
cell.businessName.text = String(user?["businessName"] as! String)
cell.businessStreet.text = String(user?["businessStreet"] as! String)
cell.businessCity.text = String(user?["businessCity"] as! String)
//cell.selectedCell.image = UIImage(named: "cellNotSelected")
let businessProfilePicture = String(user?["profPicString"] as! String)
if (businessProfilePicture.count) > 0 {
let url = URL(string: (businessProfilePicture))
DispatchQueue.global().async {
let data = try? Data(contentsOf: url!)
DispatchQueue.main.async {
let image = UIImage(data: data!)?.potter_circle
cell.businessImage.contentMode = UIView.ContentMode.scaleAspectFill
cell.businessImage.image = image
}
}
} else {
let image = UIImage(named: "default")?.potter_circle
cell.businessImage.contentMode = UIView.ContentMode.scaleAspectFill
cell.businessImage.image = image
}
//cell.profileImage.image =
//cell.businessDistance.text = String(user?["distanceLabelText"] as! String)
case .authorizedAlways, .authorizedWhenInUse:
print("Access")
print("%called")
cell.businessName.text = String(user?["businessName"] as! String)
cell.businessStreet.text = String(user?["businessStreet"] as! String)
cell.businessCity.text = String(user?["businessCity"] as! String)
cell.businessDistance.text = String(user?["distanceLabelText"] as! String)
//cell.selectedCell.image = UIImage(named: "cellNotSelected")
let businessProfilePicture = String(user?["profPicString"] as! String)
if (businessProfilePicture.count) > 0 {
let url = URL(string: (businessProfilePicture))
DispatchQueue.global().async {
let data = try? Data(contentsOf: url!)
DispatchQueue.main.async {
let image = UIImage(data: data!)?.potter_circle
cell.businessImage.contentMode = UIView.ContentMode.scaleAspectFill
cell.businessImage.image = image
}
}
} else {
let image = UIImage(named: "default")?.potter_circle
cell.businessImage.contentMode = UIView.ContentMode.scaleAspectFill
cell.businessImage.image = image
}
}
} else {
print("Location services are not enabled")
}
}
return cell
}
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
tableView.deselectRow(at: indexPath, animated: true)
let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath) as! CustomerAddSelectedBusinessesCell
let user = usersArray[indexPath.row]
let name = user!["uid"] as? String
var NSdata = NSDictionary()
var realArray = [NSDictionary]()
if let cell = tableView.cellForRow(at: indexPath as IndexPath) {
if cell.accessoryType == .checkmark{
cell.accessoryType = .none
print("Deleted \(name!)")
if let idx = data.index(of:name!) {
data.remove(at: idx)
print(data)
}
} else {
cell.accessoryType = .checkmark
data.append(name!)
print(data)
}
}
print(data)
}
Selected Cells after view loads
Cells that appear to selected but are not
It's most common cell reusable issue. Cells which are visible to screen will be reused when you scroll.
Eg. You've 5 cells visible. when you select 2,3 and scroll down 7,8 will be selected.
To avoid this you've 2 options.
You can use external Bool array to manage this(Bool array count must be same as your array count).
You can put bool variable in your user dictionary to manage that.
So whenever your scroll, newly visible cell will not selected automatically.
I am trying to show multiple locations which saved in Mysql using the code below. The data is loading but I have no idea how to show multiple locations depending on latitude and longitude.
Mysql is connected to application via PHP file.
Here is my code, the part which I called from NSObject:
func downloadItems() {
// the download function
// return the nsuserdefaults which hold the lati and longi from the notification table
UserDefaults.standard.string(forKey: "test");
let myUrl = UserDefaults.standard.string(forKey: "test");
let urlPath: String = myUrl!
let url: URL = URL(string: urlPath)!
let defaultSession = Foundation.URLSession(configuration: URLSessionConfiguration.default)
let task = defaultSession.dataTask(with: url) { (data, response, error) in
if error != nil {
print("Failed to download data")
}else {
print("Data downloaded")
self.parseJSON(data!)
}
}
task.resume()
}
func parseJSON(_ data:Data) {
var jsonResult = NSArray()
do{
jsonResult = try JSONSerialization.jsonObject(with: data, options:JSONSerialization.ReadingOptions.allowFragments) as! NSArray
} catch let error as NSError {
print(error)
}
var jsonElement = NSDictionary()
let locations = NSMutableArray()
for i in 0 ..< jsonResult.count
{
jsonElement = jsonResult[i] as! NSDictionary
let location = LocationModel()
//the following insures none of the JsonElement values are nil through optional binding
if let evIdL = jsonElement["id"] as? String,
let evUserNameL = jsonElement["username"] as? String,
let evNotikindL = jsonElement["notikind"] as? String,
let evLatiL = jsonElement["lati"] as? String,
let evLongiL = jsonElement["longi"] as? String,
let evLocatL = jsonElement["locat"] as? String,
let evTimedateL = jsonElement["timedate"] as? String,
let evDistanceL = jsonElement["distance"] as? String
{
location.evId = evIdL
location.evUsername = evUserNameL
location.evNotikind = evNotikindL
location.evLati = evLatiL
location.evLongi = evLongiL
location.evLocat = evDistanceL
location.evTimedate = evTimedateL
location.evDisatnce = evDistanceL
location.evLocat = evLocatL
}
locations.add(location)
}
DispatchQueue.main.async(execute: { () -> Void in
self.delegate.itemsDownloaded(items: locations)
})
}
}
I have no idea how to show few location on map.
try this code....
var locations = NSMutableArray()
var mapView = GMSMapView()
for i in 0..< location.count{
let obj = location[i]
lat = obj["lati"] as? Double
lng = obj["longi"] as? Double
let markerPoint = GMSMarker()
markerPoint.position = CLLocationCoordinate2D(latitude: lat!, longitude: lng!)
markerPoint.iconView = self.avtarImage() // Your image name
markerPoint.map = mapView // your mapview object name
markerPoint.zIndex = Int32(i)
markerPoint.infoWindowAnchor = CGPoint(x: 0, y: 0)
markerPoint.accessibilityLabel = String(format: "%d", i)
}
I want to return the var isConnected to outside the function to call that in a button if its true or not.
func checkReachability(isConnected: #escaping (Bool)->()) -> Bool {
var wifiMessage = ""
var isConnected = false
if currentReachabilityStatus == .reachableViaWiFi {
print("User is connected to the internet via wifi.")
let interface = CNCopySupportedInterfaces()
for i in 0..<CFArrayGetCount(interface) {
let interfaceName: UnsafeRawPointer = CFArrayGetValueAtIndex(interface, i)
let rec = unsafeBitCast(interfaceName, to: AnyObject.self)
if let unsafeInterfaceData = CNCopyCurrentNetworkInfo("\(rec)" as CFString), let interfaceData = unsafeInterfaceData as? [String : AnyObject] {
// connected wifi
wifiMessage = (String(describing: interfaceData["SSID"]))
SSIDAtual.text = "Conexão Atual:"+wifiMessage
StatusCon.text = "Status da Conexão: Conectado."
print(wifiMessage as Any)
isConnected = true
}
}
} else {
SSIDAtual.text = "Conexão Atual: Nenhuma Conexão."
StatusCon.text = "Status da Conexão: Desconectado."
print("There is no internet connection")
isConnected = false
}
print(isConnected)
return isConnected
}
And I want to call the bool inside the while in a Button action:
#IBAction func LoginWEP(_ sender: Any) {
let SSID = SSIDText.text
let Pass = PassText.text
var cont:Int
cont = 0
let contf:Int
contf = 10
let wifiConfig = NEHotspotConfiguration(ssid: SSID!, passphrase: Pass!, isWEP: true)
wifiConfig.joinOnce = false
NEHotspotConfigurationManager.shared.apply(wifiConfig) { error in
if let error = error{
print("Error: " + (error.localizedDescription))
}else {
while cont < contf{
sleep(1)
cont += 1
}
print("Connected.")
}
}
self.view.endEditing(true)
}
Depending on the task, you can go several ways:
1)
Use global variable
var isConnected: Bool?
func checkReachability() {
var wifiMessage = ""
if currentReachabilityStatus == .reachableViaWiFi {
...
self.isConnected = true
}
} else {
...
self.isConnected = false
}
print(isConnected)
return isConnected
}
Usage:
NEHotspotConfigurationManager.shared.apply(wifiConfig) { error in
...
isConnected(self.isConnected)
}
}
2) Return value in closure
Your function:
func checkReachability(completion: #escaping (_ isConnected: Bool) -> Void) {
var wifiMessage = ""
if currentReachabilityStatus == .reachableViaWiFi {
print("User is connected to the internet via wifi.")
let interface = CNCopySupportedInterfaces()
for i in 0..<CFArrayGetCount(interface) {
let interfaceName: UnsafeRawPointer = CFArrayGetValueAtIndex(interface, i)
let rec = unsafeBitCast(interfaceName, to: AnyObject.self)
if let unsafeInterfaceData = CNCopyCurrentNetworkInfo("\(rec)" as CFString), let interfaceData = unsafeInterfaceData as? [String : AnyObject] {
// connected wifi
wifiMessage = (String(describing: interfaceData["SSID"]))
SSIDAtual.text = "Conexão Atual:"+wifiMessage
StatusCon.text = "Status da Conexão: Conectado."
print(wifiMessage as Any)
completion(true)
}
}
} else {
SSIDAtual.text = "Conexão Atual: Nenhuma Conexão."
StatusCon.text = "Status da Conexão: Desconectado."
print("There is no internet connection")
completion(false)
}
}
Usage:
checkReachability { (isConnected) in
//Your code
}
I am trying to create VPN connection in my app. I go through this link
https://developer.apple.com/documentation/networkextension/nevpnmanager
but did not find any official code to use NEVPNManager and even not found any tutorial to use this NEVPNManager.
I am new to VPN concept and don't know that much about it. so Can anyone give some solutions?
Here is a IKEv2 configuration of VPN using Network Extension (Without shared key and certificate) in Swift 4.2:
final class VPNHandler {
let vpnManager = NEVPNManager.shared()
func initVPNTunnelProviderManager() {
print("CALL LOAD TO PREFERENCES...")
self.vpnManager.loadFromPreferences { (error) -> Void in
if((error) != nil) {
print("VPN Preferences error: 1")
} else {
let IKEv2Protocol = NEVPNProtocolIKEv2()
IKEv2Protocol.username = vpnUser.username
IKEv2Protocol.serverAddress = vpnServer.serverID //server tunneling Address
IKEv2Protocol.remoteIdentifier = vpnServer.remoteID //Remote id
IKEv2Protocol.localIdentifier = vpnUser.localID //Local id
IKEv2Protocol.deadPeerDetectionRate = .low
IKEv2Protocol.authenticationMethod = .none
IKEv2Protocol.useExtendedAuthentication = true //if you are using sharedSecret method then make it false
IKEv2Protocol.disconnectOnSleep = false
//Set IKE SA (Security Association) Params...
IKEv2Protocol.ikeSecurityAssociationParameters.encryptionAlgorithm = .algorithmAES256
IKEv2Protocol.ikeSecurityAssociationParameters.integrityAlgorithm = .SHA256
IKEv2Protocol.ikeSecurityAssociationParameters.diffieHellmanGroup = .group14
IKEv2Protocol.ikeSecurityAssociationParameters.lifetimeMinutes = 1440
//IKEv2Protocol.ikeSecurityAssociationParameters.isProxy() = false
//Set CHILD SA (Security Association) Params...
IKEv2Protocol.childSecurityAssociationParameters.encryptionAlgorithm = .algorithmAES256
IKEv2Protocol.childSecurityAssociationParameters.integrityAlgorithm = .SHA256
IKEv2Protocol.childSecurityAssociationParameters.diffieHellmanGroup = .group14
IKEv2Protocol.childSecurityAssociationParameters.lifetimeMinutes = 1440
let kcs = KeychainService()
//Save password in keychain...
kcs.save(key: "VPN_PASSWORD", value: vpnUser.password)
//Load password from keychain...
IKEv2Protocol.passwordReference = kcs.load(key: "VPN_PASSWORD")
self.vpnManager.protocolConfiguration = IKEv2Protocol
self.vpnManager.localizedDescription = "Safe Login Configuration"
self.vpnManager.isEnabled = true
self.vpnManager.isOnDemandEnabled = true
//print(IKEv2Protocol)
//Set rules
var rules = [NEOnDemandRule]()
let rule = NEOnDemandRuleConnect()
rule.interfaceTypeMatch = .any
rules.append(rule)
print("SAVE TO PREFERENCES...")
//SAVE TO PREFERENCES...
self.vpnManager.saveToPreferences(completionHandler: { (error) -> Void in
if((error) != nil) {
print("VPN Preferences error: 2")
} else {
print("CALL LOAD TO PREFERENCES AGAIN...")
//CALL LOAD TO PREFERENCES AGAIN...
self.vpnManager.loadFromPreferences(completionHandler: { (error) in
if ((error) != nil) {
print("VPN Preferences error: 2")
} else {
var startError: NSError?
do {
//START THE CONNECTION...
try self.vpnManager.connection.startVPNTunnel()
} catch let error as NSError {
startError = error
print(startError.debugDescription)
} catch {
print("Fatal Error")
fatalError()
}
if ((startError) != nil) {
print("VPN Preferences error: 3")
//Show alert here
print("title: Oops.., message: Something went wrong while connecting to the VPN. Please try again.")
print(startError.debugDescription)
} else {
//self.VPNStatusDidChange(nil)
print("Starting VPN...")
}
}
})
}
})
}
} //END OF .loadFromPreferences //
}
//MARK:- Connect VPN
static func connectVPN() {
VPNHandler().initVPNTunnelProviderManager()
}
//MARK:- Disconnect VPN
static func disconnectVPN() {
VPNHandler().vpnManager.connection.stopVPNTunnel()
}
//MARK:- check connection staatus
static func checkStatus() {
let status = VPNHandler().vpnManager.connection.status
print("VPN connection status = \(status.rawValue)")
switch status {
case NEVPNStatus.connected:
print("Connected")
case NEVPNStatus.invalid, NEVPNStatus.disconnected :
print("Disconnected")
case NEVPNStatus.connecting , NEVPNStatus.reasserting:
print("Connecting")
case NEVPNStatus.disconnecting:
print("Disconnecting")
default:
print("Unknown VPN connection status")
}
}
}
Code for keychain:
//MARK:- Variables for keychain access
// Identifiers
let serviceIdentifier = "MySerivice"
let userAccount = "authenticatedUser"
let accessGroup = "MySerivice"
// Arguments for the keychain queries
var kSecAttrAccessGroupSwift = NSString(format: kSecClass)
let kSecClassValue = kSecClass as CFString
let kSecAttrAccountValue = kSecAttrAccount as CFString
let kSecValueDataValue = kSecValueData as CFString
let kSecClassGenericPasswordValue = kSecClassGenericPassword as CFString
let kSecAttrServiceValue = kSecAttrService as CFString
let kSecMatchLimitValue = kSecMatchLimit as CFString
let kSecReturnDataValue = kSecReturnData as CFString
let kSecMatchLimitOneValue = kSecMatchLimitOne as CFString
let kSecAttrGenericValue = kSecAttrGeneric as CFString
let kSecAttrAccessibleValue = kSecAttrAccessible as CFString
class KeychainService: NSObject {
func save(key:String, value:String) {
let keyData: Data = key.data(using: String.Encoding(rawValue: String.Encoding.utf8.rawValue), allowLossyConversion: false)!
let valueData: Data = value.data(using: String.Encoding(rawValue: String.Encoding.utf8.rawValue), allowLossyConversion: false)!
let keychainQuery = NSMutableDictionary();
keychainQuery[kSecClassValue as! NSCopying] = kSecClassGenericPasswordValue
keychainQuery[kSecAttrGenericValue as! NSCopying] = keyData
keychainQuery[kSecAttrAccountValue as! NSCopying] = keyData
keychainQuery[kSecAttrServiceValue as! NSCopying] = "VPN"
keychainQuery[kSecAttrAccessibleValue as! NSCopying] = kSecAttrAccessibleAlwaysThisDeviceOnly
keychainQuery[kSecValueData as! NSCopying] = valueData;
// Delete any existing items
SecItemDelete(keychainQuery as CFDictionary)
SecItemAdd(keychainQuery as CFDictionary, nil)
}
func load(key: String)->Data {
let keyData: Data = key.data(using: String.Encoding(rawValue: String.Encoding.utf8.rawValue), allowLossyConversion: false)!
let keychainQuery = NSMutableDictionary();
keychainQuery[kSecClassValue as! NSCopying] = kSecClassGenericPasswordValue
keychainQuery[kSecAttrGenericValue as! NSCopying] = keyData
keychainQuery[kSecAttrAccountValue as! NSCopying] = keyData
keychainQuery[kSecAttrServiceValue as! NSCopying] = "VPN"
keychainQuery[kSecAttrAccessibleValue as! NSCopying] = kSecAttrAccessibleAlwaysThisDeviceOnly
keychainQuery[kSecMatchLimit] = kSecMatchLimitOne
keychainQuery[kSecReturnPersistentRef] = kCFBooleanTrue
var result: AnyObject?
let status = withUnsafeMutablePointer(to: &result) { SecItemCopyMatching(keychainQuery, UnsafeMutablePointer($0)) }
if status == errSecSuccess {
if let data = result as! NSData? {
if let value = NSString(data: data as Data, encoding: String.Encoding.utf8.rawValue) {
//print(value)
}
return data as Data;
}
}
return "".data(using: .utf8)!;
}
}
This tutorial help me to create VPN connection.
http://blog.moatazthenervous.com/create-a-vpn-connection-with-apple-swift/
VPN file for connection and disconnection
import Foundation
import NetworkExtension
// MARK: - NEVPNManager
// MARK: -
private var vpnLoadHandler: (Error?) -> Void { return
{ (error:Error?) in
if ((error) != nil) {
print("Could not load VPN Configurations")
self.removeToast()
return;
}
self.showToast(msg: STRINGVALUES.kCreatingConnection)
//VPN connection via Username password
let p = NEVPNProtocolIPSec()
let kcs = KeychainService()
p.authenticationMethod = NEVPNIKEAuthenticationMethod.sharedSecret
//For the security purpose added word xyz in password .so it should be remove while connecting
if self.selectedSever != nil{
self.selectedSever?.password = (self.selectedSever?.password.replacingOccurrences(of: "xyz", with: ""))!
p.username = self.selectedSever?.userName
p.serverAddress = self.selectedSever?.serverAddress
kcs.save(key: "SHARED", value: (self.selectedSever?.password)!)
kcs.save(key: "VPN_PASSWORD", value: (self.selectedSever?.password)!)
p.sharedSecretReference = kcs.load(key: STRINGVALUES.kShared)
p.passwordReference = kcs.load(key: STRINGVALUES.kVPN_Pswd)
p.useExtendedAuthentication = true
p.disconnectOnSleep = false
// Check for free subscriber
if self.selectedSever?.serverType == STRINGVALUES.VIP.lowercased() && !Singleton.checkForPaidReciept(){
self.disconnectVPN()
Helper.showAlert(sender: self, title: STRINGVALUES.AppName, message: AlertMessage.kValidateSubscription)
return
}
self.vpnManager.protocolConfiguration = p
self.vpnManager.localizedDescription = STRINGVALUES.AppName
self.vpnManager.isEnabled = true
self.vpnManager.saveToPreferences(completionHandler: self.vpnSaveHandler)
}else{
}
}
}
private var vpnSaveHandler: (Error?) -> Void { return
{ (error:Error?) in
if (error != nil) {
print("Could not save VPN Configurations")
self.removeToast()
return
} else {
do {
try self.vpnManager.connection.startVPNTunnel()
} catch let error {
print("Error starting VPN Connection \(error.localizedDescription)");
self.removeToast()
}
}
}
//self.vpnlock = false
}
public func connectVPN() {
//For no known reason the process of saving/loading the VPN configurations fails.On the 2nd time it works
do {
try self.vpnManager.loadFromPreferences(completionHandler: self.vpnLoadHandler)
} catch let error {
print("Could not start VPN Connection: \(error.localizedDescription)" )
self.removeToast()
}
}
public func disconnectVPN() ->Void {
vpnManager.connection.stopVPNTunnel()
}
func vpnConnectionStatusChanged(){
let status = self.vpnManager.connection.status
print("VPN connection status = \(status)")
switch status {
case NEVPNStatus.connected:
showToast(msg: STRINGVALUES.kConnected)
case NEVPNStatus.invalid, NEVPNStatus.disconnected :
showToast(msg: STRINGVALUES.kDisconnected)
case NEVPNStatus.connecting , NEVPNStatus.reasserting:
showToast(msg: STRINGVALUES.kConnecting)
case NEVPNStatus.disconnecting:
showToast(msg: STRINGVALUES.kDisconnecting)
default:
print("Unknown VPN connection status")
}
}
What I want to do is pass the user location to complete my JSON URL. But the way I do it, it prints "optional(coordinate)" and I just want the coordinate wihtout the optional. I tried to erase ? but it would mark error at the moment to build.
I tried to get the user location in the func locationManager and I try to use them in the func loadGas. Any help could be of use.
import UIKit
import MapKit
import CoreLocation
class MapViewController: UIViewController,MKMapViewDelegate, CLLocationManagerDelegate,UICollectionViewDelegate, UICollectionViewDataSource {
let manager = CLLocationManager()
public let sMAGNA = "magna"
public let sPREMIUM = "premium"
public let sDIESEL = "diesel"
public let MIN_TIME: CLong = 400
private let MIN_DISTANCE: Float = 1000
private var ubicaciones_selected: [Ubicacion] = []
private var ubicaciones_magna: [Ubicacion] = []
private var ubicaciones_premium: [Ubicacion] = []
private var ubicaciones_diesel: [Ubicacion] = []
private let REQUEST_LOCATION = 1
private var latlon: String = ""
private var mType: String = "magna"
var ubicaciones:[Ubicacion] = []
var Ubigaspin = MKPointAnnotation()
#IBAction func MapType(_ sender: Any) {
if mapa.mapType == MKMapType.standard{
mapa.mapType = MKMapType.satellite
} else { mapa.mapType = MKMapType.standard
}
}
#IBOutlet var mapa: MKMapView!
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
let location = locations[0]
let span:MKCoordinateSpan = MKCoordinateSpanMake(0.01, 0.01)
let myLocation:CLLocationCoordinate2D = CLLocationCoordinate2DMake(location.coordinate.latitude, location.coordinate.longitude)
print(myLocation)
let region:MKCoordinateRegion = MKCoordinateRegionMake(myLocation, span)
mapa.setRegion(region, animated: true)
self.mapa.showsUserLocation = true
manager.stopUpdatingLocation()
}
override func viewDidLoad() {
super.viewDidLoad()
//con esto obtendremos la ubicacion del usuario
manager.delegate = self
manager.desiredAccuracy = kCLLocationAccuracyBest
manager.requestWhenInUseAuthorization()
mapa.showsUserLocation = true
manager.startUpdatingLocation()
//se cargan los pines y las gasolinas
loadGas(tipo: mType)
}
func loadGas(tipo:String){
mType = tipo
var ubicaciones:[Ubicacion] = []
switch tipo {
case sMAGNA:
ubicaciones = ubicaciones_magna
case sPREMIUM:
ubicaciones = ubicaciones_premium
case sDIESEL:
ubicaciones = ubicaciones_diesel
default:
ubicaciones = ubicaciones_magna
}
if ubicaciones.count == 0 {
let lat = String(describing: manager.location?.coordinate.latitude)
let long = String(describing: manager.location?.coordinate.longitude)
let url = URL(string: "http://192.241.214.56/api/ubicacion/?format=json&sub="+lat+","+long)
print (url)
// let url = URL(string: "http://192.241.214.56/api/ubicacion/?format=json&sub=29.08919%2C-110.96133")
// let url = URL(string: "http://192.241.214.56/api/"+tipo+"/?format=json")
URLSession.shared.dataTask(with: url!, completionHandler: {
(data, response, error) in
if(error != nil){
print("error")
}else{
do{
let ubicaciones_json = try JSONSerialization.jsonObject(with: data!, options:.allowFragments) as! [[String : AnyObject]]
for ubicacion in ubicaciones_json{
let nombre:String = ubicacion["nombre"] as! String
let direccion:String = ubicacion["direccion"] as! String
let precio_magna:Float = ubicacion["precio_magna"] as! Float
let precio_premium:Float = ubicacion["precio_premium"] as! Float
let precio_diesel:Float = ubicacion["precio_diesel"] as! Float
let ubicacion:String = ubicacion["ubicacion"] as! String
let p = Ubicacion()
p.ubicacion = ubicacion
p.setLatLng()
p.nombre = nombre
p.direccion = direccion
p.precio_magna = precio_magna
p.precio_premium = precio_premium
p.precio_diesel = precio_diesel
ubicaciones.append(p)
}
self.ubicaciones = ubicaciones
OperationQueue.main.addOperation({
self.updatePins(ubicaciones: ubicaciones)
})
}catch let error as NSError{
print(error)
}
}
}).resume()
}else{
self.ubicaciones = ubicaciones
self.updatePins(ubicaciones: ubicaciones)
}
}
Instead of
let lat = String(describing: manager.location?.coordinate.latitude)
you should do something like this:
guard let location = manager.location else {
return
}
let lat = String(format: "%f", location.coordinate.latitude)