Custom callouts in MapKit have no text in them

Hello.


I am trying to make custom callouts on my map.


func mapView(mapView: MKMapView, annotationView view: MKAnnotationView, calloutAccessoryControlTapped control: UIControl)
        {
            var calloutDetails = ""
            let annotationTapped = view.annotation as! IGAMapAnnotation
   
            if (annotationTapped.icao == appSingleton.icaoDepShared)
            {
                let facilitiesStr = appSingleton.facilitiesDepShared.joinWithSeparator("\n")
                calloutDetails = NSString(format: "DEPARTURE RUNWAYS/ILS:\n%@",facilitiesStr) as String
            }
               
            else if (annotationTapped.icao == appSingleton.icaoDestShared)
            {
                let facilitiesStr = appSingleton.facilitiesDestShared.joinWithSeparator("\n")
                calloutDetails = NSString(format: "DESTINATION RUNWAYS/ILS:\n%@",facilitiesStr) as String
            }
               
            else if (annotationTapped.icao == appSingleton.icaoAltShared)
            {
                let facilitiesStr = appSingleton.facilitiesAltShared.joinWithSeparator("\n")
                calloutDetails = NSString(format: "ALTERNATE RUNWAYS/ILS:\n%@",facilitiesStr) as String
            }
           
            // Declare and initialize the UIViewController that has the label to contain the callout information
            let detailViewController = IGAAnnotationInfoVC(calloutText: calloutDetails)
   
            if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiom.Pad)
            {
                let popOver = UIPopoverController(contentViewController: detailViewController)
               
                popOver.popoverContentSize = CGSizeMake(detailViewController.txtCallout.frame.size.width + 40,detailViewController.txtCallout.frame.size.height + 40);
               
                popOver.presentPopoverFromRect(view.bounds, inView: view, permittedArrowDirections: UIPopoverArrowDirection.Any, animated: true)
            }
        }


This is my subclassed MKAnnotation:



class IGAMapAnnotation: NSObject, MKAnnotation
    {
        let  coordinate : CLLocationCoordinate2D
        let title : String?
        var navaidType : String
        let frequency : String
        let icao : String
       
        init(coordinate: CLLocationCoordinate2D, title: String, type: String, frequency: String, icao: String)
        {
            self.title = title
            self.navaidType = type
            self.coordinate = coordinate
            self.frequency = frequency
            self.icao = icao
           
            super.init()
        }  
    }


This is my Annotation View Controller:



import UIKit
   
    class IGAAnnotationInfoVC: UIViewController
    {
        var calloutInformation : String = ""
        var txtCallout : IGACalloutLabel!
       
        init()
        {
            super.init(nibName:nil, bundle:nil)
        }
       
       
        required init?(coder aDecoder: NSCoder)
        {
            fatalError("")
        }
       
        convenience init(calloutText : String)
        {
            self.init()
            self.calloutInformation = calloutText;
            self.txtCallout = IGACalloutLabel(frame: CGRectMake(20, 20, 0, 0))
            self.txtCallout?.lineBreakMode = NSLineBreakMode.ByWordWrapping
            self.txtCallout?.numberOfLines=0;
            self.txtCallout?.backgroundColor = UIColor.clearColor()
            self.txtCallout?.textColor = UIColor.blueColor()
            self.txtCallout?.text = calloutInformation;
            self.txtCallout?.drawTextInRect(CGRectMake(10,10,0,0))
            self.txtCallout?.sizeToFit()
            self.view.addSubview(txtCallout!)
        }
    }


And this is my Custom Label Class:



import UIKit
   
    class IGACalloutLabel: UILabel
    {
        var topInset : CGFloat = 0.0
        var leftInset : CGFloat = 0.0
        var bottomInset : CGFloat = 0.0
        var rightInset : CGFloat = 0.0
        
        required init?(coder aDecoder: NSCoder)
        {
            super.init(coder:aDecoder)
            self.setup()
        }
       
        override init(frame:CGRect)
        {
            super.init(frame:frame)
            self.setup()
        }
       
        override  func awakeFromNib() {
            super.awakeFromNib()
            self.setup()
        }
   
        override class func layerClass() -> AnyClass {
            return CATextLayer.self
        }
       
        func textLayer() -> CATextLayer {
            return self.layer as! CATextLayer
        }
       
        func setup()
        {
            self.text = self.text
            self.textColor = self.textColor
            self.font = self.font
            self.textLayer().alignmentMode = kCAAlignmentLeft
            self.textLayer().wrapped = true
            self.layer.display()
        }
       
        override func drawTextInRect(rect: CGRect)
        {
            let insets = UIEdgeInsets(top: topInset, left: leftInset, bottom: bottomInset, right: rightInset)
            return super.drawTextInRect(UIEdgeInsetsInsetRect(rect, insets))
        }
       
        func sizeToFitFixedWidth()
        {
            self.frame = CGRectMake(self.frame.origin.x, self.frame.origin.y, 400, 0);
            self.lineBreakMode = NSLineBreakMode.ByWordWrapping
            self.numberOfLines = 0;
            sizeToFit()
        }
    }


This code was converted by me from Objective C. It did work in Objective C but in Swift it does not. I get the first callout view fine but when I tap on the Info button within the callout, I get a new callout view without any text in it. Not sure where the problem lies.



Thank you!

Accepted Reply

If you take out the custom UILabel subclass and just use a UILabel, does that help? Could narrow down the issue.

Replies

In that if ... else if ... else if ... statement, are you sure one of those three cases is getting hit? When you step through it in the debugger, is your text non-empty?

Sorry if I missed it, but I don't see a viewForAnnotation?


Seen this SO thread? http://stackoverflow.com/questions/24467408/swift-add-mkannotationview-to-mkmapview

No, junkpile. This is what I thought too. But in the convenience init in the IGAAnnotationInfoVC, I see that the self.txtCallout?.text in:


self.txtCallout?.text = calloutInformation;


has a String to show.


So it initializes the UIViewController but does not have a text. May there be a problem with the custom UILabel class?


Thanks for your help.

Using the view debugger and/or logging printouts, are the frames (and clipsToBounds property) of all views involved being laid out correctly?


In cases where you're reusing an annotation view, I see you're just setting the annotation property. Is that what's happening here? Is that sufficient to cause a redraw?


You are doing some pretty funky stuff there. What is the reason for stuff like this?


            self.text = self.text 
            self.textColor = self.textColor 
            self.font = self.font

self.txtCallout?.frame shows: MY CALL OUT LABEL3 Optional((20.0, 20.0, 228.0, 41.0))

detailViewController in IGAAcarsVC also shows : POPOVER: (20.0, 20.0, 228.0, 41.0)

Looks like the right size. Still no text. Again, this code did work in Objective C.


junkpile. I agree, this stuff is funky. The thing is that subclassing UILabel in Swift is insanity. I just used some code that I found online.


Changing to something like:


self.textColor = UIColor.blackColor()


...makes no difference.


Thank you.

If you take out the custom UILabel subclass and just use a UILabel, does that help? Could narrow down the issue.

Thanks a lot, junkpile, for the suggestion! I have replaced my custom UILabel with the regular UILabel and it worked!


Best.