I want to change the image of the pins on the map to individual images stored in external storage.

Asked 2 years ago, Updated 2 years ago, 69 views

Prerequisites/What you want to achieve

I am making a map application, but I would like to change the pin image to the individual image stored in FirebaseStorage.

I don't think the first half of the code is relevant, but I'm a beginner and I don't know how far to show it, so I'll reveal the whole thing.

Problems/Error Messages you are experiencing

The pin image remains the default.
The image acquisition itself seems to be working, and print(imageimageimage!) can read information about the stored image, but the actual pins remain the default.

Also, at the bottom of the build error,

Missing return in a function expected to return 'MKAnnotationView!'

appears with an error message.
I think I am doing return, but is there something wrong?

Source Codes Affected

 func mapView (mapView: MKMapView!, viewForAnnotation!) - > MKAnnotationView!{
    if notation===mapView.userLocation{//Leave default for annotations indicating current location
        return nil
    } else{
        // Replace the corresponding data in the array with a constant called item?
        let items = contentArray
        // Get images, first connect to FirebaseStorage
        let storage=Storage.storage()

        // Create a storage reference from your storage service
        let storageRef=storage.reference(forURL: "https://firebasestorage.googleapis.com/v0/b/catmap-44f0a.appspot.com/o/")

        US>for item in items {
            // Convert the contents of the item to a dictionary type?
            let content=item.value as!Dictionary<String, Any>
            for (key, element) in content {
                let pinData=content[key] as![String:Any]
                if let geohash=pinData["geohash"]as? US>String{

                    let(latitude, longitude) = Geohash.decode(hash:geohash)!
                    let announcement = MKPointAnnotation()
                    annotation.coordinate=CLLocationCoordinate2DMake (CLLocationDegrees(latitude.min), CLLocationDegrees(longitude.min))
                    announcementArray.append(announcement)

                    let reuseId="pin"
                    iflet pinView=self.mapView.dueReusableAnnotationView(withIdentifier:reuseId){
                        return pinView
                    }
                    else {// Generate if there are no reusable annotations (for example, first time)
                        let pinView = MKAnnotationView (announcement: announcement, reuseIdentifier: reuseId)

                        // Firebase Storage Image Reference
                        let catRef=storageRef.child("images/\(key)/0.jpg")

                        // fetch the download URL
                        catRef.downloadURL{(URL, error)->Void in
                            if(error!=nil){
                                // Handle any errors
                            } else{
                                // Get the download URL for 'images/stars.jpg'
                                // Generating a UIImage with a URL Example
                                let PictureURL=URL!

                                /*
                                 Create session objects with default settings.
                                  */
                                let session = URLSession(configuration:.default)
                                /*
                                 Define the download task.The download task is:
                                 Download the contents of the URL as a data object.
                                 You can do what you want with that data.
                                 */
                                let downloadPicTask = session.dataTask (with:catPictureURL) {(data, response, error) in
                                    /*
                                     The download is complete.
                                     */

                                    iflet = error {
                                        print("An error occurred while downloading cat picture:\(e)")
                                    } else{
                                        /*
                                         No errors were found.
                                         If there is no response, it will change, so please check that as well.
                                         */
                                        ifless=response as?HTTPURLResponse{
                                            print("\"(res.statusCode)"")
                                            iflet imageData=data{
                                                /*
                                                 Finally, we convert the data into an image.
                                                 I will use it to do what I want.
                                                 */

                                                let imageimage=UIImage(data:imageData)
                                                print (imageimageimage!)
                                                pinView.image=imageimage
                                                pinView.annotation=annotation

                                            } else{
                                                print("Failed to get image: no image available")
                                            }
                                        } else{
                                            print("The response code could not be retrieved for any reason")
                                        }
                                    }
                                }
                                downloadPicTask.resume()
                            }
                        }
                        return pinView
                    }
                    self.mapView.addAnnotations (announcementArray)
                }
            }
        }
    }
}

Supplementary information (e.g. language/FW/tool version)

  • swift3
  • xcode 8.3.3

swift ios xcode swift3 xcode8

2022-09-30 11:32

1 Answers

As you can see in the comments, I don't know how and from where to how it was verified, so I can't give you a specific code that can be verified, but I can't make it work without making a big correction just by looking at it.

The outline of your code is as follows:

//↓(1)
func mapView (mapView:MKMapView!, viewForAnnotation!) - > MKAnnotationView!{
    if notation===mapView.userLocation{//Leave default for annotations indicating current location
        return nil
    } else{
        // Replace the corresponding data in the array with a constant called item?
        let items = contentArray
        //...

        US>for item in items {
            // Convert the contents of the item to a dictionary type?
            let content=item.value as!Dictionary<String, Any>
            for (key, element) in content {
                let pinData=content[key] as![String:Any]
                if let geohash=pinData["geohash"]as? US>String{

                    let(latitude, longitude) = Geohash.decode(hash:geohash)!
                    letnotation=MKPointAnnotation()//->(4)
                    annotation.coordinate=CLLocationCoordinate2DMake (CLLocationDegrees(latitude.min), CLLocationDegrees(longitude.min))
                    announcementArray.append(announcement)//->(5)

                    let reuseId="pin"
                    iflet pinView=self.mapView.dueReusableAnnotationView(withIdentifier:reuseId){
                        return pinView//->(2)
                    }
                    else {// Generate if there are no reusable annotations (for example, first time)
                        let pinView = MKAnnotationView (announcement: announcement, reuseIdentifier: reuseId)

                        //...

                        return pinView//->(2)
                    }
                    self.mapView.addAnnotations(announcementArray)//->(3)
                }
            }
        }
    }
}

(1) The method header shown is up to Swift2.In Swift3, the same MKMapViewDelegate method looks like this:

 func mapView(_mapView:MKMapView, viewFornotation:MKAnnotation) ->MKAnnotationView? {
    //...
}

Swift is still a developing language, especially Swift2→3, where almost every practical app has made significant changes that need to be modified.If you're pulling a reference code from the Internet, you have to check if the article is the same version as your Swift, or you'll have to learn more about Swift's language transition history than Swift or iOS programming.Be careful.

(2) Are you writing a return statement for this method (except nil if let geohash=pinData["geohash"] as? Only if the String conditions are met.There are no return statements to run if none of the data that meets that condition exists in the contentArray.This is causing the Missing return error.

(3) You cannot normally call MKMapView.addAnnotations(_:) in the mapView(_:viewFor:) method. You can run addAnnotations(_:) somewhere else before the map appears, and the mapView(_:)method simply

(4) As I mentioned above, it is not normal to ignore the announcement parameter and create another MKPointAnnotation instance (MKPointAnnotation) within the mapView(_:viewFor:) method.

(5) I wonder if this is an instance property because I cannot find a declaration of announcementArray in the method.We have done append(_:) for this array, but we do not see any code to empty the array, which means that the array expands every time the mapView(_:viewFor:) method is called (which is called quite often during MKMapView display).

The following is a rough outline of the revised policy:

  • "Create annotations from contentArray and do addAnnotations(_:)"is another method in mapView(_:viewFor:) (viewDidLoad() of action that the annotation determines.(At this point, you create a MKAnnotation implementation class, not a MKAnnotationView.)

  • mapView(_:viewFor:) returns one MKMapAnnotationView created based on the annotation parameter. If the properties required for this purpose do not exist in the existing MKAnnotation class, create the original MKnotation.

addAnnotations(_:) by creating an annotation from contentArray is another method of mapView(_:viewFor:) (viewDidLoad() or the action method whose annotation is determined, of course not the same number of times)(At this point, MKAnnotation is an implementation class, not MKAnnotationView.)

mapView(_:viewFor:) returns one MKMapAnnotationView created based on the annotation parameter, creating the original MKAnnotation class if the required properties do not exist in the existing class.

Since it will require a major revision, if you can modify the code to the extent that the compilation can pass based on the above policy, you should ask a separate question, even if there is still a difference from the desired behavior.


2022-09-30 11:32

If you have any answers or tips


© 2024 OneMinuteCode. All rights reserved.