IOS SWIFT - Query Attachment from feature table

573
1
10-30-2018 12:57 AM
MohamedMuzammil
New Contributor

Hi,

IOS SWIFT

I want to query features with attachments. 

I have tried to use the sample edit data attachment but not successful.

When I using the identify layer, am able to get the attachment, but I want to achieve through query layers. Below are the code, I have tried.

 

    

    var featureTable: AGSServiceFeatureTable!

    featureTable = AGSServiceFeatureTable(url: URL(string: layoutMapping.offersURL)!)

    let featureLayer = AGSFeatureLayer(featureTable: featureTable)

    let map = AGSMap()

    let mapImageLayer = AGSArcGISTiledLayer(url: URL(string: layoutMapping.arcGISURL)!)

    map.operationalLayers.add(mapImageLayer)

    map.operationalLayers.add(featureLayer)

    

    self.mapViews.map = map

    

    let layers:[AGSLayer]! =  map.operationalLayers as! [AGSLayer]

    

    

    let featureLayer1:AGSFeatureLayer = layers[1] as! AGSFeatureLayer

    

    

    

    let queryParams = AGSQueryParameters()

    let query = "1=1"

    queryParams.whereClause = query

    

    

    

    

    let table1 = featureLayer1.featureTable as! AGSServiceFeatureTable

    table1.queryFeatures(with: queryParams, queryFeatureFields: .loadAll, completion: { (result:AGSFeatureQueryResult?, error:Error?) -> Void in

        

        

        

        if error != nil {

            let alert = UIAlertController(title: self.layoutMapping.appTitle, message: "Server Connection Failed!", preferredStyle: .alert)

            alert.addAction(UIAlertAction(title: "Ok", style: .default, handler: nil))

            self.present(alert, animated: true)

        }

        else if let features = result?.featureEnumerator().allObjects as? [AGSArcGISFeature] , features.count > 0 {

            

           

            

            for feature in features

            {

                var imageList = [UIImage]()

                

                guard let arcgisFeature = feature as? AGSArcGISFeature else {

                    print("test")

                }

                

                feature.fetchAttachments { (attachments:[AGSAttachment]?, error:Error?) -> Void in

                    if let error = error {

                        print(error)

                    }

                    else if let attachments = attachments {

                        print(attachments.count)

                        

                        

                        let attachment = attachments[0]

                        attachment.fetchData { (data:Data?, error:Error?) -> Void in

                            if let error = error {

                                print(error)

                            }

                            else if let data = data {

                                let image = UIImage(data: data)!

                                //cell.imageView?.image = image

                                imageList.append(image)

                            }

                        }

                    }

                    

                    

                }

            }

            

        }

        

    })

  

Please provide your answer.

Thanks

0 Kudos
1 Reply
Nicholas-Furness
Esri Regular Contributor

The problem you're seeing is that each AGSArcGISFeature is going out of scope and being deallocated before the async fetchAttachments call is completing. You could try something like this, which uses Swift closure captures to hold a reference to a feature until the fetchAttachments call has completed.

func getAttachments() {
    let params = AGSQueryParameters()
    params.whereClause = "1=1"
    
    table.queryFeatures(with: params, queryFeatureFields: .loadAll) { (results, error) in
        guard error == nil else {
            print("Error querying features: \(error!.localizedDescription)")
            return
        }
        
        guard let featureEnumerator = results?.featureEnumerator() else { return }
        
        // Create a Set to store feature references
        var featuresHavingAttachmentsFetched = Set<AGSArcGISFeature>()
        
        var i = 0
        
        for result in featureEnumerator {
            guard let feature = result as? AGSArcGISFeature else { continue }
            
            // Store the feature reference in the set
            featuresHavingAttachmentsFetched.insert(feature)
            print("Getting attachments for feature \(i).")
            
            // Call fetch attachments, but also capture `feature` so that it can be removed from the
            // set maintaining the reference to it once the attachment fetch completes.
            feature.fetchAttachments() { [feature, i] (attachments, error) in
                defer {
                    // Remove the feature reference when this fetchAttachments callback block exits.
                    // We've held on to it long enough now and don't need it any more.
                    featuresHavingAttachmentsFetched.remove(feature)
                }

                guard error == nil else {
                    print("Error getting attachments for feature \(i): \(error!.localizedDescription)")
                    return
                }
                
                print("Got \(attachments?.count ?? 0) attachments for feature \(i).")
            }
            
            i += 1
        }
    }
}
‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍

Cheers,

Nick.

0 Kudos