I have a question regarding creating a Apple Map Overlay. I am trying to set on odd shape overlay from a JSON file. I have researched this on Stack Overflow, and have tried many of the solutions, but none seem to work. My code is below:
import UIKit
import MapKit
import CoreLocation
class ViewController: UIViewController, CLLocationManagerDelegate, MKMapViewDelegate, UIGestureRecognizerDelegate {
#IBOutlet weak var mapView: MKMapView!
var coordinate: CLLocationCoordinate2D?
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
mapView.showsUserLocation = true
mapView.delegate = self
mapView.mapType = .standard
let gestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(self.TapGesture))
mapView.addGestureRecognizer(gestureRecognizer)
}
func mapView(_ mapView: MKMapView, rendererFor overlay: MKOverlay) -> MKOverlayRenderer {
if overlay is MKPolygon {
let polygonView = MKPolygonRenderer(overlay: overlay)
polygonView.strokeColor = UIColor.black
polygonView.lineWidth = 0.5
polygonView.fillColor = UIColor.blue
return polygonView
}
return MKOverlayRenderer()
}
#objc func TapGesture(gesRect: UITapGestureRecognizer) {
let location = gesRect.location(in: mapView)
coordinate = mapView.convert(location,toCoordinateFrom: mapView)
let locCoord = mapView.convert(location, toCoordinateFrom: mapView)
print("Tapped at lat: \(locCoord.latitude) long: \(locCoord.longitude)")
print("Tapped at: \(location)")
self.retreiveShape() { (full_shape) in
if let shape = full_shape {
let polygon = MKPolygon.init(coordinates: shape, count: shape.count)
self.mapView.addOverlay(polygon)
} else {
print("ARRAY EMPTY")
}
}
}
func retreiveShape(completion: #escaping ([CLLocationCoordinate2D]?) -> ()) {
let path = Bundle.main.path(forResource: "shape", ofType: "json")
var coord_array = [CLLocationCoordinate2D]()
do {
let data = try Data.init(contentsOf: URL.init(fileURLWithPath: path!))
let json = try JSONSerialization.jsonObject(with: data, options: .allowFragments)
if let dictionary = json as? [String: Any] {
if let shape = dictionary["shape"] as? Array<Any> {
for regions in shape {
guard let region = regions as? Array<Array<Array<Double>>> else {
print("NOT HAPPENING")
return
}
for sections in region {
for coord in sections {
print("LATITUDE: \(coord[0])", "LONGITUDE: \(coord[1])")
let coordinatesToAppend = CLLocationCoordinate2D(latitude: coord[0], longitude: coord[1])
coord_array.append(coordinatesToAppend)
}
}
}
completion(coord_array)
}
}
} catch let error {
print(error)
}
}
The shape.json file is below:
{
"shape":[
[
[
[-81.621199, 30.282314],
[-81.613987, 30.281941],
[-81.611277, 30.284743],
[-81.602735, 30.284026],
[-81.601978, 30.292561],
[-81.596275, 30.290861],
[-81.592406, 30.290182],
[-81.571146, 30.28763],
[-81.55922, 30.286602],
[-81.559148, 30.291132],
[-81.558633, 30.294747],
[-81.55881, 30.312887],
[-81.558601, 30.312888],
[-81.558622, 30.316235],
[-81.558313, 30.316828],
[-81.552252, 30.320252],
[-81.548471, 30.321618],
[-81.527882, 30.323989],
[-81.529486, 30.328076],
[-81.537635, 30.336704],
[-81.537706, 30.337221],
[-81.538717, 30.338277],
[-81.539343, 30.338462],
[-81.542809, 30.341686],
[-81.547286, 30.345211],
[-81.552498, 30.348839],
[-81.552559, 30.352445],
[-81.577566, 30.352039],
[-81.578098, 30.353324],
[-81.578161, 30.35642],
[-81.577294, 30.3596],
[-81.576996, 30.366609],
[-81.58011, 30.366553],
[-81.580875, 30.37062],
[-81.580844, 30.373862],
[-81.581462, 30.374486],
[-81.578114, 30.374236],
[-81.572908, 30.374611],
[-81.562232, 30.372303],
[-81.551965, 30.366559],
[-81.548676, 30.365568],
[-81.540187, 30.378172],
[-81.538175, 30.380467],
[-81.538213, 30.387239],
[-81.536613, 30.388739],
[-81.512612, 30.392739],
[-81.505211, 30.390739],
[-81.490911, 30.392139],
[-81.49085, 30.389014],
[-81.489978, 30.389207],
[-81.488818, 30.38775],
[-81.489203, 30.389266],
[-81.487056, 30.390019],
[-81.481446, 30.391262],
[-81.479505, 30.39117],
[-81.477708, 30.390635],
[-81.476792, 30.390609],
[-81.476244, 30.391002],
[-81.473212, 30.389422],
[-81.472125, 30.388436],
[-81.472225, 30.388071],
[-81.474072, 30.386758],
[-81.475085, 30.384287],
[-81.474394, 30.381898],
[-81.473246, 30.38059],
[-81.473337, 30.380112],
[-81.47295, 30.379864],
[-81.472643, 30.380053],
[-81.471914, 30.379532],
[-81.471629, 30.378346],
[-81.470845, 30.377256],
[-81.468671, 30.376016],
[-81.466871, 30.374481],
[-81.465402, 30.374424],
[-81.464374, 30.373764],
[-81.465116, 30.373015],
[-81.467728, 30.372493],
[-81.469102, 30.371435],
[-81.470279, 30.369931],
[-81.472008, 30.370608],
[-81.473695, 30.370041],
[-81.471862, 30.370238],
[-81.470952, 30.369737],
[-81.471715, 30.369462],
[-81.470506, 30.369378],
[-81.469456, 30.368207],
[-81.468051, 30.367707],
[-81.46754, 30.366828],
[-81.466905, 30.366464],
[-81.467432, 30.366219],
[-81.466928, 30.365735],
[-81.465222, 30.365136],
[-81.464909, 30.364103],
[-81.46316, 30.362764],
[-81.463369, 30.36188],
[-81.462197, 30.361235],
[-81.461151, 30.36123],
[-81.46117, 30.360531],
[-81.461878, 30.360305],
[-81.461619, 30.359642],
[-81.461873, 30.358669],
[-81.461645, 30.358376],
[-81.460504, 30.358329],
[-81.46288, 30.357969],
[-81.462786, 30.357137],
[-81.461247, 30.355282],
[-81.460556, 30.352518],
[-81.46184, 30.340222],
[-81.462497, 30.339325],
[-81.465064, 30.337897],
[-81.471588, 30.328301],
[-81.472988, 30.318258],
[-81.469123, 30.319481],
[-81.450496, 30.320896],
[-81.443818, 30.302908],
[-81.442451, 30.301512],
[-81.438991, 30.299798],
[-81.437921, 30.298031],
[-81.437696, 30.284657],
[-81.438134, 30.283427],
[-81.439935, 30.281191],
[-81.440578, 30.279729],
[-81.440309, 30.276152],
[-81.441217, 30.271746],
[-81.440891, 30.270368],
[-81.440247, 30.269313],
[-81.438555, 30.267721],
[-81.43765, 30.266188],
[-81.43705, 30.257116],
[-81.441869, 30.256519],
[-81.45385, 30.252008],
[-81.466184, 30.251073],
[-81.472173, 30.251296],
[-81.491372, 30.251034],
[-81.507105, 30.253603],
[-81.510744, 30.253761],
[-81.530261, 30.250144],
[-81.56957, 30.249854],
[-81.584658, 30.251369],
[-81.586895, 30.251326],
[-81.589607, 30.250593],
[-81.593308, 30.248471],
[-81.605497, 30.260294],
[-81.621493, 30.282334],
[-81.621199, 30.282314]
]
]
]
}
It should create an odd shape overlay in the Southside of Jacksonville,FL, but it isn't. When the completion block is called the Coordinates are added to the array, but the map overlay isn't showing. Any thoughts?
Well this is somewhat embarrassing. I did as was suggested in the comments, and tried having the shape with nine vertices. It still didn't work. I then changed the coord from:
print("LATITUDE: \(coord[0])", "LONGITUDE: \(coord[1])")
let coordinatesToAppend = CLLocationCoordinate2D(latitude: coord[0], longitude: coord[1])
to:
print("LATITUDE: \(coord[1])", "LONGITUDE: \(coord[0])")
let coordinatesToAppend = CLLocationCoordinate2D(latitude: coord[1], longitude: coord[0])
It works perfectly. Turns out I had the Latitude and Longitude wrong.
I am implementing UserNotification in my app. When the notification gets fired it shows two action, in one i want to add snooze effect, it must snooze after 5 mins again. How to handle it ? thanks for all ! help if any one do have idea
Well to snooze notification you can create another notification with same details of current notification and increase the fire date by 5 mins.
Here is the code I used :
func snoozeScheduledNotification(notification:UILocalNotification) -> Void {
// Snooze for 10 mins
let localNotification = UILocalNotification()
localNotification.fireDate = notification.fireDate?.addingTimeInterval(60*10)
localNotification.repeatInterval = NSCalendar.Unit(rawValue: 0) // 0 = No Repeat
localNotification.alertBody = notification.alertBody
localNotification.soundName = notification.soundName
localNotification.userInfo = notification.userInfo
localNotification.category = notification.category
UIApplication.shared.scheduleLocalNotification(localNotification)
}
Hope it helps you.
The shortest and simplest code I found about it
For Swift 3/4
extension UNNotification {
func snoozeNotification(for hours: Int, minutes: Int, seconds: Int) {
let content = UNMutableNotificationContent()
content.title = "Another Alert"
content.body = "Your message"
content.sound = .default()
let identifier = self.request.identifier
guard let oldTrigger = self.request.trigger as? UNCalendarNotificationTrigger else {
debugPrint("Cannot reschedule notification without calendar trigger.")
return
}
var components = oldTrigger.dateComponents
components.hour = (components.hour ?? 0) + hours
components.minute = (components.minute ?? 0) + minutes
components.second = (components.second ?? 0) + seconds
let trigger = UNCalendarNotificationTrigger(dateMatching: components, repeats: false)
let request = UNNotificationRequest(identifier: identifier, content: content, trigger: trigger)
UNUserNotificationCenter.current().add(request) { error in
if let error = error {
debugPrint("Rescheduling failed", error.localizedDescription)
} else {
debugPrint("rescheduled success")
}
}
}
}
You just need to call it this way :
response.notification.snoozeNotification(for: 0, minutes: 0, seconds: 30)
Credit goes to Simon Ljungberg : https://gist.github.com/simme/96264d5ceee394083d18e2c64f42a3a9
For iOS10, use this code.
Use this code in AppDelegate.swift file.
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey : Any]? = nil) -> Bool {
let center = UNUserNotificationCenter.current()
let category = UNNotificationCategory(identifier: "identifier", actions: [], intentIdentifiers: [])
center.setNotificationCategories([category])
center.requestAuthorization(options: [.badge, .alert , .sound]) { (greanted, error) in
print(error)
}
return true
}
You can put this code in any view controller.
let content = UNMutableNotificationContent.init()
content.title = "Notification Title"
content.subtitle = "Notification Sub-Title"
content.body = "Notification Body"
content.sound = UNNotificationSound.default()
let trigger = UNTimeIntervalNotificationTrigger(timeInterval: 5, repeats: false)
let request = UNNotificationRequest(identifier: "identifier", content: content, trigger: trigger)
UNUserNotificationCenter.current().add(request) { error in
UNUserNotificationCenter.current().delegate = self
if (error != nil){
//handle here
}
}
You can handle notification using following method:
extension UIViewController: UNUserNotificationCenterDelegate {
public func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: #escaping (UNNotificationPresentationOptions) -> Swift.Void) {
completionHandler( [.alert, .badge, .sound])
}
public func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: #escaping () -> Swift.Void) {
print("Tapped in notification")
}
}
You can use this Blog as reference and Example.
I am using calling feature in App . Problem is that if no sim card installed in device then "No sim card installed" Alert view showing 2 times . I am using this code :
if ([[UIApplication sharedApplication] canOpenURL:[NSURL URLWithString:phoneNumber]])
{
[[UIApplication sharedApplication] openURL:[NSURL URLWithString:phoneNumber]];
}
Note: 1st Alert view automatically hide and again 2nd one is appearing .
Finally Found alternate solution for this :
Actually this is not an issue , This is transition effect :
To resolve it i have integrated below code before calling feature :
#import CoreTelephony;
CTTelephonyNetworkInfo *networkInfo = [CTTelephonyNetworkInfo new];
CTCarrier *carrier = [networkInfo subscriberCellularProvider];
if (!carrier.isoCountryCode) {
UIAlertView *alert = [[UIAlertView alloc]initWithTitle:#"No SIM Card Installed" message:nil delegate:nil cancelButtonTitle:#"OK" otherButtonTitles:nil, nil];
[alert show];
}
else{
[[UIApplication sharedApplication] openURL:[NSURL URLWithString:phoneNumber]];
}
import UIKit
import Alamofire
import NVActivityIndicatorView
import Reachability
//pod 'NVActivityIndicatorView'
//pod 'Alamofire', '~> 4.0'
//pod 'ReachabilitySwift'
typealias CompletionHandler = (_ success:Bool,_ reponsedata:Data) -> Void
typealias CompletionHandlerJson = (_ success:Bool,_ reponsedata:NSMutableDictionary) -> Void
typealias ResponseHandler = (_ success:Bool,_ data:NSData, _ error : String) -> Void
typealias ConnectivityHandler = (_ success:Bool) -> Void
class Connectivity {
class func internetConnection(completionHandler: #escaping ConnectivityHandler) {
//var Status:Bool = false
let url = NSURL(string: "http://google.com/")
let request = NSMutableURLRequest(url: url! as URL)
request.httpMethod = "HEAD"
request.cachePolicy = NSURLRequest.CachePolicy.reloadIgnoringLocalAndRemoteCacheData
request.timeoutInterval = 1.0
let session = URLSession.shared
session.dataTask(with: request as URLRequest as URLRequest, completionHandler: {(data, response, error) in
if let httpResponse = response as? HTTPURLResponse {
if httpResponse.statusCode == 200 {
completionHandler(true)
}
}
completionHandler(false)
}).resume()
}
class func connetivityAvailable() ->Bool {
return NetworkReachabilityManager()!.isReachable
}
}
class WebserviceHelper: NSObject {
class func postWebServiceCall(urlString:String, parameters:[String:AnyObject], encodingType: String, ShowProgress:Bool, completionHandler: #escaping CompletionHandler){
if Connectivity.connetivityAvailable() == false {
log(message: "internet is not available.")
HUD.hide()
AppDelegate.showMessage(message:NO_INTERNET_AVAILABLE)
completionHandler(false,Data())
return
}
if ShowProgress {
HUD.show(.systemActivity)
}
log(message: "\(urlString): + parametersnew")
let encoding: ParameterEncoding!
if encodingType == DefaultEncoding{
encoding = JSONEncoding.default
}else{
encoding = URLEncoding.httpBody
}
Alamofire.request(urlString, method: HTTPMethod.post, parameters: parameters, encoding: encoding , headers: HelperClass.sharedInstance.getApiHeader()).responseData(completionHandler: { (response) in
if response.result.isSuccess {
if ShowProgress {
HUD.hide()
}
if let result = response.result.value {
completionHandler(true,result)
}
}
if response.result.isFailure {
if ShowProgress{
HUD.hide()
}
print("Lost Connection %#",urlString)
if let responseCode = response.response?.statusCode as Int?{
print("Lost Connection with code %#",response.result.value as Any)
let responseDic = NSMutableDictionary()
responseDic.setObject(responseCode, forKey: "statusCode" as NSCopying)
completionHandler(false,Data())
}
completionHandler(false,Data())
}
})
}
class func postWebServiceJson(urlString:String, parameters:[String:AnyObject], encodingType: String, ShowProgress:Bool, completionHandler: #escaping CompletionHandlerJson){
if Connectivity.connetivityAvailable() == false {
AppDelegate.showMessage(message:NO_INTERNET_AVAILABLE)
completionHandler(false,NSMutableDictionary())
return
}
if ShowProgress {
HUD.show(.systemActivity)
}
log(message: "\(urlString): + parametersnew")
let encoding: ParameterEncoding!
if encodingType == DefaultEncoding{
encoding = JSONEncoding.default
}else{
encoding = URLEncoding.httpBody
}
Alamofire.request(urlString, method: HTTPMethod.post, parameters: parameters, encoding: encoding , headers: HelperClass.sharedInstance.getApiHeader()).responseJSON { (response) in
if response.result.isSuccess {
if ShowProgress {
HUD.hide()
}
if let result = response.result.value as? NSDictionary {
completionHandler(true,NSMutableDictionary(dictionary: result))
}
}
if response.result.isFailure {
if ShowProgress{
HUD.hide()
}
print("Lost Connection %#",urlString)
if let responseCode = response.response?.statusCode as Int?{
print("Lost Connection with code %#",response.result.value as Any)
let responseDic = NSMutableDictionary()
responseDic.setObject(responseCode, forKey: "statusCode" as NSCopying)
completionHandler(false,NSMutableDictionary())
}
completionHandler(false,NSMutableDictionary())
}
}
}
class func WebapiGetMethod(strurl:String, ShowProgress: Bool = false, completionHandler: #escaping CompletionHandlerJson){
if Connectivity.connetivityAvailable() == false {
log(message:"internet is not available.")
completionHandler(false,NSMutableDictionary())
//.. AppDelegate .showMessage(message:"Please check your internet connection")
return
}
if ShowProgress{
HUD.show(.systemActivity)
}
Alamofire.request(strurl).responseJSON { response in
if let status = response.response?.statusCode {
switch(status){
case 200:
if let result = response.result.value {
if let JSONdict = result as? NSMutableDictionary{
DispatchQueue.main.async {
completionHandler(true,JSONdict)
}
}
if ShowProgress {
HUD.hide()
}
}else{
if ShowProgress {
HUD.hide()
}
completionHandler(false,NSMutableDictionary())
}
log(message:"example success")
default:
log(message:"error with get response status: \(status)")
DispatchQueue.main.async {
if ShowProgress {
HUD.hide()
}
}
completionHandler(false,NSMutableDictionary())
}
}
DispatchQueue.main.async {
if ShowProgress {
HUD.hide()
}
}
}
}
class func getWebServiceCall(urlString:String,ShowProgress:Bool, completionHandler: #escaping CompletionHandler){
if Connectivity.connetivityAvailable() == false {
log(message: "internet is not available.")
HUD.hide()
AppDelegate.showMessage(message:NO_INTERNET_AVAILABLE)
completionHandler(false,Data())
return
}
if ShowProgress {
HUD.show(.systemActivity)
}
log(message: "\(urlString): + parametersnew")
Alamofire.request(urlString, method: .get, parameters: nil, encoding: URLEncoding.methodDependent, headers: HelperClass.sharedInstance.getApiHeader()).responseData { (response) in
if response.result.isSuccess {
if ShowProgress {
HUD.hide()
}
if let result = response.result.value {
completionHandler(true,result)
}
}
if response.result.isFailure {
if ShowProgress{
HUD.hide()
}
print("Lost Connection %#",urlString)
if let responseCode = response.response?.statusCode as Int?{
print("Lost Connection with code %#",response.result.value as Any)
let responseDic = NSMutableDictionary()
responseDic.setObject(responseCode, forKey: "statusCode" as NSCopying)
completionHandler(false,Data())
}
completionHandler(false,Data())
}
}
}
}