I'm redoing the navigation of my app to be based on a custom UITabBarController. The tab bar opens the various ViewController. This is working fine, however Im now getting errors with the code in the ViewController that was previously working.
The new customTabBarController
import UIKit
class CustomTabBarController: UITabBarController {
override func viewDidLoad() {
super.viewDidLoad()
let feedController = feedVC() //Name of the view controller
let firstNavigationController = UINavigationController(rootViewController: feedController)
firstNavigationController.title = "Feed"
firstNavigationController.tabBarItem.image = UIImage(named: "feed_icon")
let clubController = moreVC() //Name of the view controller
let secondNavigationController = UINavigationController(rootViewController: clubController)
secondNavigationController.title = "Club"
secondNavigationController.tabBarItem.image = UIImage(named: "club_icon")
let recordController = moreVC() //Name of the view controller
let thirdNavigationController = UINavigationController(rootViewController: recordController)
thirdNavigationController.title = "Record"
thirdNavigationController.tabBarItem.image = UIImage(named: "record_icon")
let profileController = moreVC() //Name of the view controller
let fourthNavigationController = UINavigationController(rootViewController: profileController)
fourthNavigationController.title = "Profile"
fourthNavigationController.tabBarItem.image = UIImage(named: "profile_icon")
let moreController = moreVC() //Name of the view controller
let fifthNavigationController = UINavigationController(rootViewController: moreController)
fifthNavigationController.title = "More"
fifthNavigationController.tabBarItem.image = UIImage(named: "more_icon")
viewControllers = [firstNavigationController, secondNavigationController, thirdNavigationController, fourthNavigationController, fifthNavigationController]
tabBar.isTranslucent = false
// Color of menu bar set in AppDelegate.swift
}
}
feedVC
import UIKit
import Firebase
class feedVC: UIViewController {
#IBOutlet weak var tableView: UITableView!
var activityArray = [Activity]()
var userdataArray = [Userdata]()
var cellSpacingHeight: CGFloat = 10 // Sets the spacing between the cells
override func viewDidLoad() {
super.viewDidLoad()
if Auth.auth().currentUser == nil {
let authVC = self.storyboard?.instantiateViewController(withIdentifier: "authVC") as? authVC
self.present(authVC!, animated: true, completion: nil)
}
tableView.delegate = self
tableView.dataSource = self
}
The error I get is:
Thread 1: EXC_BREAKPOINT (code=1, subcode=0x102eb7b50) linked to the below code in the feedVC.
tableView.delegate = self
tableView.dataSource = self
The second error I get is related to recordVC
import UIKit
import MapKit
class recordVC: UIViewController, MKMapViewDelegate {
#IBOutlet weak var mapView: MKMapView!
var tileRenderer: MKTileOverlayRenderer!
// set initial location in Aspøya
let initialLocation = CLLocation(latitude: 63.011018, longitude: 7.914721)
// Set the zoom level of the location
let regionRadius: CLLocationDistance = 1000
func centerMapOnLocation(location: CLLocation) {
let coordinateRegion = MKCoordinateRegionMakeWithDistance(location.coordinate,
regionRadius, regionRadius)
mapView.setRegion(coordinateRegion, animated: true)
}
func setupTileRenderer() {
// Fetching the map file from URL below. The {x}, {y}, and {z} are replaced at runtime by an individual tile’s coordinate. The z-coordinate, or zoom-level is specified by how much the user has zoomed in the map. The x and y are the index of the tile given the section of the Earth shown. A tile needs to be supplied for every x and y for each zoom level supported.
let template = "https://opencache.statkart.no/gatekeeper/gk/gk.open_gmaps?layers=norgeskart_bakgrunn&zoom={z}&x={x}&y={y}&format=image/png"
// Creates the overlay
let overlay = MKTileOverlay(urlTemplate: template)
// Indicates the tiles are opaque and replace the default map tiles
overlay.canReplaceMapContent = true
// Adds the overlay to the mapView
mapView.add(overlay, level: .aboveLabels)
// Creates a tile renderer which handles the drawing of the tiles.
tileRenderer = MKTileOverlayRenderer(tileOverlay: overlay)
}
This give a similar error of: hread 1: EXC_BREAKPOINT (code=1, subcode=0x10561bb50) for this code line
// Adds the overlay to the mapView
mapView.add(overlay, level: .aboveLabels)
For the first one you have to use UITableViewDelegate and UITableViewDataSource like below :
class feedVC: UIViewController, UITableViewDelegate, UITableViewDataSource {
....
}
For the second, You have to do UI operations on main thread.
DispatchQueue.main.async {
mapView.add(overlay, level: .aboveLabels)
}
Related
I am trying to create an app that creates random pictures when a button is clicked. The app is working fine but I see this message which I have never seen before."Publish changes from background threads is not allowed; make sure to publish values from the main thread.".
I am new to SwiftUI, help is appreciated.
import Foundation
import SwiftUI
class ImageviewModel{
var image: UIImage? = nil
//let url = URL(string: "https://source.unsplash.com/random/600x600")!
let url = URL(string: "https://picsum.photos/600/600")!
func responseHandler(data: Data?, response: URLResponse?) ->
UIImage?{
guard let data = data,
let image = UIImage(data: data),
let response = response else {return nil}
return image
}
func loadImageWithAsync() async throws -> UIImage?{
do{
let (data, response) = try await URLSession.shared.data(from: url,delegate: nil)
return responseHandler(data: data, response: response)
} catch{
throw error
}
}
}
class ViewModel: ObservableObject{
#Published var image: UIImage? = nil
var loader = ImageviewModel()
func fetchImage() async {
let image = try? await loader.loadImageWithAsync()
self.image = image
}
}
You need to add the MainActor wrapper to the class to guarantee that updates are done on Main
#MainActor
class ViewModel: ObservableObject{
Goal: SceneKit hit test with SwiftUI (instead of UIKit)
Problem: When I embed the default ship scene on a SwiftUI "UIViewRepresentable", the example handleTap function doesn't work. and I get his error:
"Argument of '#selector' refers to instance method 'handleTap' that is not exposed to Objective-C"
How an I create a hit test, and pass data to another SwiftUI view?
import SwiftUI
import SceneKit
var handleTap: (() -> Void)
struct ScenekitView : UIViewRepresentable {
let scene = SCNScene(named: "ship.scn")!
func makeUIView(context: Context) -> SCNView {
// create and add a camera to the scene
let cameraNode = SCNNode()
cameraNode.camera = SCNCamera()
scene.rootNode.addChildNode(cameraNode)
// place the camera
cameraNode.position = SCNVector3(x: 0, y: 0, z: 15)
// retrieve the ship node
let ship = scene.rootNode.childNode(withName: "ship", recursively: true)!
// retrieve the SCNView
let scnView = SCNView()
return scnView
}
func updateUIView(_ scnView: SCNView, context: Context) {
scnView.scene = scene
// allows the user to manipulate the camera
scnView.allowsCameraControl = true
// show statistics such as fps and timing information
scnView.showsStatistics = true
// configure the view
scnView.backgroundColor = UIColor.black
// add a tap gesture recognizer
let tapGesture = UITapGestureRecognizer(target: self, action: #selector(handleTap(_:)))
scnView.addGestureRecognizer(tapGesture)
}
func handleTap(_ gestureRecognize: UIGestureRecognizer) {
// retrieve the SCNView
let scnView = SCNView()
// check what nodes are tapped
let p = gestureRecognize.location(in: scnView)
let hitResults = scnView.hitTest(p, options: [:])
// check that we clicked on at least one object
if hitResults.count > 0 {
// retrieved the first clicked object
let result = hitResults[0]
// get material for selected geometry element
let material = result.node.geometry!.firstMaterial
// highlight it
SCNTransaction.begin()
SCNTransaction.animationDuration = 0.5
// on completion - unhighlight
SCNTransaction.completionBlock = {
SCNTransaction.begin()
SCNTransaction.animationDuration = 0.5
material?.emission.contents = UIColor.black
SCNTransaction.commit()
}
material?.emission.contents = UIColor.green
SCNTransaction.commit()
}
}
}
#if DEBUG
struct ScenekitView_Previews : PreviewProvider {
static var previews: some View {
ScenekitView()
}
}
#endif
Just hit this issue myself and finally found a solution: make a dummy struct that pulls from a class that actually holds your SCNView.
This works for me:
struct ScenekitView : UIViewRepresentable {
let scenekitClass = ScenekitClass()
func makeUIView(context: Context) -> SCNView {
return scenekitClass.view
}
func updateUIView(_ scnView: SCNView, context: Context) {
// your update UI view contents look like they can all be done in the initial creation
}
}
class ScenekitClass {
let view = SCNView()
let scene = SCNScene(named: "ship.scn")!
init() {
// create and add a camera to the scene
let cameraNode = SCNNode()
cameraNode.camera = SCNCamera()
scene.rootNode.addChildNode(cameraNode)
// place the camera
cameraNode.position = SCNVector3(x: 0, y: 0, z: 15)
// attach the scene
view.scene = scene
// allows the user to manipulate the camera
view.allowsCameraControl = true
// show statistics such as fps and timing information
view.showsStatistics = true
// configure the view
view.backgroundColor = UIColor.black
// add a tap gesture recognizer
let tapGesture = UITapGestureRecognizer(target: self, action: #selector(handleTap(_:)))
view.addGestureRecognizer(tapGesture)
}
#objc func handleTap(_ gestureRecognize: UIGestureRecognizer) {
// check what nodes are tapped
let p = gestureRecognize.location(in: view)
let hitResults = view.hitTest(p, options: [:])
// check that we clicked on at least one object
if hitResults.count > 0 {
// retrieved the first clicked object
let result = hitResults[0]
// get material for selected geometry element
let material = result.node.geometry!.firstMaterial
// highlight it
SCNTransaction.begin()
SCNTransaction.animationDuration = 0.5
// on completion - unhighlight
SCNTransaction.completionBlock = {
SCNTransaction.begin()
SCNTransaction.animationDuration = 0.5
material?.emission.contents = UIColor.black
SCNTransaction.commit()
}
material?.emission.contents = UIColor.green
SCNTransaction.commit()
}
}
}
Based on this question.
For whatever reason, the SwiftUI SceneView does not conform to the SCNSceneRenderer protocol. If it did, then it would not be necessary to make use of a UIViewRepresentable (or NSViewRepresentable for macOS) view.
I have a complete example app, for macOS, here:
https://github.com/Thunor/HitTestApp
SceneView has a delegate argument. You can use a SCNSceneRenderDelegate to capture the SCNSceneRenderer and use it for hit testing. Here's an example:
import SwiftUI
import SceneKit
import Foundation
class RenderDelegate: NSObject, SCNSceneRendererDelegate {
// dummy render delegate to capture renderer
var lastRenderer: SCNSceneRenderer!
func renderer(_ renderer: SCNSceneRenderer, updateAtTime time: TimeInterval) {
// store the renderer for hit testing
lastRenderer = renderer
}
}
class Model: ObservableObject {
let scene = SCNScene(named: "scene.usdz")!
let renderDelegate = RenderDelegate()
}
struct ContentView: View {
#ObservedObject var model = Model()
var body: some View {
SceneView(scene: model.scene, options: [.allowsCameraControl, .autoenablesDefaultLighting], delegate: model.renderDelegate)
.gesture(
SpatialTapGesture(count: 1)
.onEnded(){ event in
// hit test
guard let renderer = model.renderDelegate.lastRenderer else { return }
let hits = renderer.hitTest(event.location, options: nil)
if let tappedNode = hits.first?.node {
// do something
}
}
)
}
}
I need current location as a source and searched location as a destination, but I got the current location but here I am unable to bring coordinates(latitude and longitude) from searched location to destination.
here my destination shows nil why?
Below is the code please help me.
import UIKit
import MapKit
import CoreLocation
class MapSampViewController: UIViewController, CLLocationManagerDelegate, MKMapViewDelegate, UISearchBarDelegate {
//Privacy - Location When In Use Usage Description, Privacy - Location Always Usage Description-------these two add in info.plist
#IBOutlet weak var searchBar: UISearchBar!
#IBOutlet weak var mapView: MKMapView!
var source: CLLocationCoordinate2D!
var destination: CLLocationCoordinate2D!
var myaddress:String!
var mycity:String!
var mystate:String!
var mycountry:String!
var mytitle:String!
var mylongitude:String!
var mylatitude:String!
var locationtoSearch:String!
let locationManager = CLLocationManager()
var currentlocationPlacemark: CLPlacemark!
override func viewDidLoad() {
super.viewDidLoad()
searchBar.delegate = self
mapView.delegate = self
mapView.showsScale = true
mapView.showsPointsOfInterest = true
mapView.showsUserLocation = true
if CLLocationManager.locationServicesEnabled()
{
locationManager.delegate = self
locationManager.desiredAccuracy = kCLLocationAccuracyBest
locationManager.startUpdatingLocation()
}
// self.showDirection()
}
func searchBarSearchButtonClicked(_ searchBar: UISearchBar) {
locationtoSearch = self.searchBar.text
var geocoder:CLGeocoder = CLGeocoder()
geocoder.geocodeAddressString(locationtoSearch!, completionHandler: {(placemarks, error) -> Void in
if((error) != nil)
{
print("Error", error)
}
else if let placemark = placemarks?[0] as? CLPlacemark {
var coordinates:CLLocationCoordinate2D = placemark.location!.coordinate
var pointAnnotation:MKPointAnnotation = MKPointAnnotation()
pointAnnotation.coordinate = coordinates
print(coordinates)
// pointAnnotation.title = "\(String(describing: placemark.name)),\(String(describing: placemark.locality)), \(String(describing: placemark.administrativeArea)), \(String(describing: placemark.country))"
self.myaddress = placemark.name
self.mycity = placemark.locality
self.mystate = placemark.administrativeArea
self.mycountry = placemark.country
pointAnnotation.title = "\(self.myaddress),\(self.mycity),\(self.mystate),\(self.mycountry)"
self.mylongitude = String(stringInterpolationSegment: placemark.location?.coordinate.longitude)
self.mylatitude = String(stringInterpolationSegment: placemark.location?.coordinate.latitude)
self.mapView?.addAnnotation(pointAnnotation)
self.mapView?.centerCoordinate = coordinates
print("coordinates \(coordinates)")
print("The latitude \(self.mylatitude)")
print("The longitude \(self.mylongitude)")
self.mapView?.selectAnnotation(pointAnnotation, animated: true)
}
})
self.showDirection()//i called here or in view viewDidLoad
let annotationsToRemove = mapView.annotations.filter { $0 !== self.mapView.userLocation
}
mapView.removeAnnotations( annotationsToRemove )
}
func showDirection()
{
source = locationManager.location?.coordinate//17.6881° N, 83.2131° E
// let destination = CLLocationCoordinate2DMake(24.9511, 121.2358 )//If i give like this its working
destination = CLLocationCoordinate2DMake(Double(mylongitude)!, Double(mylongitude)!)//fatal error: unexpectedly found nil while unwrapping an Optional value
let sourcePlacemark = MKPlacemark(coordinate: source!)
let destinationPlacemark = MKPlacemark(coordinate: destination)
let sourceItem = MKMapItem(placemark: sourcePlacemark)
let destinationItem = MKMapItem(placemark: destinationPlacemark)
let directionReq = MKDirectionsRequest()
directionReq.source = sourceItem
directionReq.destination = destinationItem
directionReq.transportType = .automobile
let directions = MKDirections(request: directionReq)
directions.calculate(completionHandler: {(response, error) in
if error != nil {
print("Error getting directions")
}
else {
let route = response?.routes[0]
self.mapView.add((route?.polyline)!, level:.aboveRoads)
let rekt = route?.polyline.boundingMapRect
self.mapView.setRegion(MKCoordinateRegionForMapRect(rekt!), animated: true)
}
})
}
func mapView(_ mapView: MKMapView, rendererFor overlay: MKOverlay) -> MKOverlayRenderer {
let rendrer = MKPolylineRenderer(overlay: overlay)
rendrer.strokeColor = UIColor.blue
rendrer.lineWidth = 3
return rendrer
}
}
here i called showDirection() func in searchBarSearchButtonClicked but it is getting called before coming here why?
Direction requests are executed asynchronously. This means that the rest of your app doesn't wait for the direction to be fetched.
Your showDirection function is both fetching the direction and adding it to the mapView. It would be best to separate these functionalities. You can fetch the direction, update a route variable and have an observer on it which will add the route to the map once it has been fetched.
#IBOutlet weak var mapView: MKMapView!
var route: MKRoute? {
didSet {
mapView.add((route?.polyline)!, level:.aboveRoads) }
}
I can't seem to make this tableView with custom cells work. I get a runtime error
Terminating app due to uncaught exception 'NSUnknownKeyException',
reason: '[ setValue:forUndefinedKey:]: this class is not key
value coding-compliant for the key causeCampaignDescription.'
The weird thing is that that property is not called like that anymore. This is the cell file MainViewControllerTableViewCell
//
// MainViewControllerTableViewCell.swift
//
//
// Created by on 9/13/17.
// Copyright © 201. All rights reserved.
//
import UIKit
class MainViewControllerTableViewCell: UITableViewCell {
#IBOutlet weak var causeCampaignImageView: UIImageView!
#IBOutlet weak var causeDescription: UILabel!
#IBOutlet weak var daysToFinishLabel: UILabel!
#IBOutlet weak var raisedOverTotalLabel: UILabel!
#IBOutlet weak var percentageCompletedLabel: UILabel!
#IBOutlet weak var goalProgresView: UIProgressView!
//card used on
#IBInspectable var cornerradius : CGFloat = 2
#IBInspectable var shadowOffSetWidth : CGFloat = 0
#IBInspectable var shadowOffSetHeight : CGFloat = 5
#IBInspectable var shadowColor : UIColor = UIColor.black
#IBInspectable var shadowOpacity : CGFloat = 0.5
override func awakeFromNib() {
super.awakeFromNib()
// Initialization code
}
override func setSelected(_ selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
// Configure the view for the selected state
}
override func layoutSubviews() {
layer.cornerRadius = cornerradius
layer.shadowColor = shadowColor.cgColor
layer.shadowOffset = CGSize(width: shadowOffSetWidth, height: shadowOffSetHeight)
let shadowPath = UIBezierPath(roundedRect: bounds, cornerRadius: cornerradius)
layer.shadowPath = shadowPath.cgPath
layer.shadowOpacity = Float(shadowOpacity)
}
}
and this is the view controller that holds the table view MainViewController:
//
// ViewController.swift
//
//
// Created by on 1/28/17.
// Copyright © 2017. All rights reserved.
//
import UIKit
import Alamofire
import SwiftyJSON
import Firebase
class MainViewController: UIViewController,UITableViewDelegate,UITableViewDataSource {
var campaignRowsData = [CauseCampaign]()
var serverFetchCampaignsUrl = Config.Global._serverUrl
#IBOutlet weak var campaignTableView: UITableView!
//show navigation controller bar
var facebookID = "", twitterID = "",firebaseID = ""
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
//hide bar from navigation controller
setToolbar()
campaignTableView.delegate=self
campaignTableView.dataSource=self
campaignTableView.separatorColor = UIColor(white: 0.95, alpha: 1)
recoverUserDefaults()
getCampaignList()
//print(facebookID, twitterID, firebaseID)
}
func setToolbar(){
//hide bar from navigation controller
self.navigationController?.isNavigationBarHidden = false
self.navigationItem.setHidesBackButton(true, animated: false)
self.navigationController?.navigationBar.barTintColor = UIColor.purple
}
func getCampaignList(){
Alamofire.request(serverFetchCampaignsUrl+"/campaigns/get/all/user/\(twitterID)/firebase/\(firebaseID)/cat/0", method: .get).validate().responseJSON { response in
switch response.result {
case .success(let data):
let campaignCausesJSON = JSON(campaignCausesData: data)
self.parseCampaignCausesListResponse(campaignCausesJSON)
//alternative thread operation
DispatchQueue.main.async {
self.campaignTableView.reloadData()
}
case .failure(let error):
print(error)
}
}
}
func parseCampaignCausesListResponse(_ campaignCausesJSON:JSON){
if let activeCampaignCount = campaignCausesJSON["active_campaigns_count"].string {
//Now you got your value
print("TOTAL_ACTIVE_CAMPAIGNS",activeCampaignCount)
CampaignsGlobalDataManagerUtil.campaignTotalCount = Int(activeCampaignCount)!
}
if let contributorUserId = campaignCausesJSON["contributor_user_id"].string {
//Now you got your value
print("CONTRIBUTOR_USER_ID",contributorUserId)
CurrentUserUtil.contributorUserId = contributorUserId
}
if let userTwitterFollowersQty = campaignCausesJSON["user_twitter_followers_qty"].int {
//Now you got your value
print("USER_TWITTER_FOLLOWERS_QTY",userTwitterFollowersQty)
CurrentUserUtil.twitterFollowersCount = Int(userTwitterFollowersQty)
}
//Parsing campaigns object array
campaignCausesJSON["camp_array"].arrayValue.map({
let campaignCause:JSON = $0
parseCampaign(campaignCause)
})
}
//TODO:CHANGE TO DATATAPE OBJECT
func parseCampaign(_ causeCampaign:JSON){
let causeCampaignObject: CauseCampaign = CauseCampaign();
causeCampaignObject.description = causeCampaign["cause_description"].stringValue
causeCampaignObject.id = causeCampaign["campaign_id"].stringValue
if let contributorsQty = causeCampaign["contributors_qty"].int{
causeCampaignObject.contributorsQty = contributorsQty
}
causeCampaignObject.currencySymbol = causeCampaign["currency_symbol"].stringValue
if let currentContributions = causeCampaign["current_contributions"].float{
causeCampaignObject.currentContributions = currentContributions
}
if let goal = causeCampaign["goal"].float {
causeCampaignObject.goal = goal
}
if let goalPercentageAchieved = causeCampaign["goal_percentage_achieved"].float{
causeCampaignObject.goalPercentageAchieved = causeCampaign["goal_percentage_achieved"].float!
}
causeCampaignObject.hashtag = causeCampaign["hashtag"].stringValue
causeCampaignObject.name = causeCampaign["name"].stringValue
if let remainingAmmountToGoal = causeCampaign["remaining_ammount_to_goal"].float{
causeCampaignObject.remainingAmmountToGoal = remainingAmmountToGoal
}
if let picUrl = causeCampaign["pic_url"].stringValue as? String {
causeCampaignObject.picUrl = picUrl
}
if let campaignStartingDate = causeCampaign["created_at"].string{
causeCampaignObject.campaignStartingDate = campaignStartingDate
}
if let campaignEndingDate = causeCampaign["campaign_ending_date"].string{
causeCampaignObject.campaignEndingDate = campaignEndingDate
}
var foundationsArray = [Foundation]()
causeCampaign["foundations"].arrayValue.map({
let id = $0["foundation_id"].stringValue
let twitterUsername = $0["twitter_username"].stringValue
let picPath = $0["pic_path"].stringValue
let name = $0["name"].stringValue
let foundation:Foundation = Foundation(id,twitterAccount: twitterUsername,picPath: picPath,name: name)
foundationsArray.append(foundation)
})
causeCampaignObject.foundations = foundationsArray
campaignRowsData.append(causeCampaignObject)
// foundations = "<null>";
//innecesario
// SACAR DE LA REQUEST INICIAL???
// "went_inactive_date" = "<null>";
// "tweet_id" = 900936910494810112;
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return campaignRowsData.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = campaignTableView.dequeueReusableCell(withIdentifier: "campaignCell", for: indexPath) as! MainViewControllerTableViewCell
//setting card attributes
print("ROW",campaignRowsData[indexPath.row].description)
let campaignCause:CauseCampaign = campaignRowsData[indexPath.row]
if let desc = campaignCause.description as? String{
cell.causeDescription.text = desc
} else {
print("NULL")
}
return cell
}
func recoverUserDefaults(){
if let fbID = UserDefaults.standard.object(forKey: Config.Global._facebookIdUserDefaults) as? String {
facebookID = fbID
}else{
print("FACEBOOK ID IS NULL")
}
if let twtID = UserDefaults.standard.object(forKey: Config.Global._twitterIdUserDefaults) as? String{
twitterID = twtID
}else{
print("TWITTER ID IS NULL")
}
if let firID = UserDefaults.standard.object(forKey: Config.Global._firebaseIdUserDefaults) as? String{
firebaseID = firID
}else{
print("TWITTER ID IS NULL")
}
return
}
}
The app crashes if the line reloadData is uncommented (I don't even know when and If I should use this)
If I set a label you can't see anything on screen, I see blank cards, but again, as soon as I uncomment reloadData it crashes
There's no causeCampaignDescription, now it's called causeDescription so I don't know why the error keeps mentioning that field
The data desc is ok since I printed it and it has the right content so it's not that
What could be the problem?
Searching the project for causeCampaignDescription will often turn up the offending xib and/or storyboard containing the outdated key path. However, it's been my experience that Xcode is not always 100% reliable about finding things in xibs and storyboards, so if Xcode's search feature won't find it, this command in the Terminal will turn it up straightaway:
find /path/to/your/project/directory -name .git -prune -or -type f -exec grep causeCampaignDescription {} \; -print
Once you find the offending item in the xib or storyboard, change it to the correct string and you should solve your problem.
Having problem in displaying polyline on the mapview
Following this tutorial
MapView Tutorial
Attached is my code.
Annotation is appearing on the map but unable to call the renderer method. Though the delegate is there.
Main Problem: Unable to draw line between two coordinates
Console Output: 2017-02-06 22:54:56.770584 MapTest[2329:805733] [LogMessageLogging] 6.1 Unable to retrieve CarrierName. CTError: domain-2, code-5, errStr:((os/kern) failure)
Here is the code
import UIKit
import MapKit
class ViewController: UIViewController,MKMapViewDelegate {
#IBOutlet weak var myMap: MKMapView!
override func viewDidLoad() {
super.viewDidLoad()
// 1.
myMap.delegate = self
// 2.
let sourceLocation = CLLocationCoordinate2D(latitude: 40.759011, longitude: -73.984472)
let destinationLocation = CLLocationCoordinate2D(latitude: 40.748441, longitude: -73.985564)
// 3.
let sourcePlacemark = MKPlacemark(coordinate: sourceLocation, addressDictionary: nil)
let destinationPlacemark = MKPlacemark(coordinate: destinationLocation, addressDictionary: nil)
// 4.
let sourceMapItem = MKMapItem(placemark: sourcePlacemark)
let destinationMapItem = MKMapItem(placemark: destinationPlacemark)
// 5.
let sourceAnnotation = MKPointAnnotation()
sourceAnnotation.title = "Times Square"
if let location = sourcePlacemark.location {
sourceAnnotation.coordinate = location.coordinate
}
let destinationAnnotation = MKPointAnnotation()
destinationAnnotation.title = "Empire State Building"
if let location = destinationPlacemark.location {
destinationAnnotation.coordinate = location.coordinate
}
// 6.
self.myMap.showAnnotations([sourceAnnotation,destinationAnnotation], animated: true )
// 7.
let directionRequest = MKDirectionsRequest()
directionRequest.source = sourceMapItem
directionRequest.destination = destinationMapItem
directionRequest.transportType = .automobile
// Calculate the direction
let directions = MKDirections(request: directionRequest)
// 8.
directions.calculate {
(response, error) -> Void in
guard let response = response else {
if let error = error {
print("Error: \(error)")
}
return
}
let route = response.routes[0]
self.myMap.add((route.polyline), level: MKOverlayLevel.aboveRoads)
let rect = route.polyline.boundingMapRect
self.myMap.setRegion(MKCoordinateRegionForMapRect(rect), animated: true)
}
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func mapView(mapView: MKMapView, rendererForOverlay overlay: MKOverlay) -> MKOverlayRenderer {
print("Line 85 is being called......start...")
let renderer = MKPolylineRenderer(overlay: overlay)
renderer.strokeColor = UIColor.red
renderer.lineWidth = 4.0
print("Line 85 is being called.......end..")
return renderer
}
}
Your rendererForOverlay function has the wrong syntax; Xcode told me this when testing your code. Use
func mapView(_ mapView: MKMapView, rendererFor overlay: MKOverlay) -> MKOverlayRenderer
Instead, and a line will be drawn between the two points.