Skip To Content

Working with an attachment manager

In this topic

An attachment manager simplifies working with attachments. It provides a convenient, coarse-grained API to retrieve, add, and delete attachments. An attachment manager builds on the functionality provided by a feature layer to manage attachments and does all the heavy-lifting for you behind the scenes.

Getting an attachment manager

An attachment manager is associated with a single feature belonging to a feature layer. All attachments belonging to this feature can be managed through an attachment manager. To get a handle to an attachment manager for a feature, you need to invoke the attachmentManagerForFeature: method on AGSFeatureLayer.

//The feature layer from which we will get an attachment manager
let featureLayer:AGSFeatureLayer = ...
        
//The ID of the feature whose attachment manager we want
let fid = 1
let feature = featureLayer.lookupFeatureWithObjectId(fid)
        
let attMgr = featureLayer.attachmentManagerForFeature(feature)
A feature layer keeps track of all the attachment managers it hands out. These attachment managers are cleared when the layer is deallocated. To manually clear an attachment manager that is no longer needed, you can invoke the appropriate clearAttachmentManager methods on AGSFeatureLayer.
//clear all attachment managers
featureLayer.clearAttachmentManagers()
        
//or clear a specific one
featureLayer.clearAttachmentManagerForFeatureWithObjectId(fid)
Note:

When an attachment manager is cleared, any local changes it's holding on to are lost. You can invoke hasLocalEdits on AGSAttachmentManager to check if it has any local changes before clearing it.

Retrieving attachments

Once you have a handle to a feature's attachment manager, you can use it to retrieve attachments belonging to that feature. Retrieving attachments is a two step process.

1. Retrieving attachment metadata

You first need to retrieve metadata about the feature's attachments by invoking downloadAttachmentInfos on AGSAttachmentManager.

attMgr.downloadAttachmentInfos()

Metadata contains information about how many attachments a feature has (if any), the IDs of those attachments, name, and so on. This metadata is captured in AGSAttachmentInfo objects.

The attachment manager's delegate is notified via the attachmentManager:didDownloadAttachmentInfos: method when the operation completes.

If metadata is retrieved successfully, AGSAttachmentInfo objects containing the metadata are passed into this method. In addition, the attachments property on AGSAttachmentManager is populated with empty AGSAttachment objects containing only metadata.

If an error is encountered, the downloadAttachmentInfosError property on AGSAttachmentManager is populated providing more information about the error. A delegate should always inspect this property and handle errors appropriately.

2. Retrieving attachment data

For each attachment with data you want to retrieve, you need to invoke downloadAttachmentDataForId: on AGSAttachmentManager. You need to pass in the ID of the attachment. The ID is available in the attachment metadata.

//The attachment whose data to download
let att:AGSAttachment = ...
        
attMgr.downloadAttachmentDataForId(att.attachmentInfo.attachmentId)

The attachment manager's delegate is notified via the attachmentManager:didDownloadDataForAttachment: method when the operation completes.

If data is retrieved successfully, you can invoke the data method on individual AGSAttachment objects to get their raw data. To conserve memory, an attachment manager persists the data for each attachment to temporary files on disk. These files are automatically cleaned up when the attachment manager is cleared.

If an error is encountered, the networkError property on individual AGSAttachment objects is populated providing more information about the error. A delegate should always inspect this property and handle errors appropriately.

To cancel any outstanding download operations, be it to retrieve attachment metadata or the actual attachment data, you can invoke the cancelAllDownloadDataOperations, cancelDownloadDataForId:, or cancleDownloadAttachmentInfos method on AGSAttachmentManager.

Adding attachments

To add a new attachment for a feature, you need to invoke the appropriate addAttachment method on AGSAttachmentManager.

//Adding image
let image:UIImage = ...
attMgr.addAttachmentAsJpgWithImage(image, name: "My House.jpg")
        
//Adding any binary data, for instance, pdf
let data:NSData = ...
attMgr.addAttachmentWithData(data, name: "Deed.pdf", contentType: "application/pdf")

When the method completes, an AGSAttachment object representing the attachment is returned. The object is also added to the attachment manager's attachments list. The object's editState property is set to AGSAttachmentEditStateAdded.

At this point, the attachment exists only on the device. If the application is closed or the device powers down, the attachment will be lost. To save the new attachment on the server, you need to post it as described in the Committing changes to the server section in this topic. After the attachment is saved on the server, the attachment object's editState property is set to AGSAttachmentEditStateOriginal.

Deleting attachments

To delete an existing attachment for a feature, you need to invoke markAttachment:forDeletion: on AGSAttachmentManager.

//attachment to be deleted
let att:AGSAttachment = ...
attMgr.markAttachment(att, forDeletion: true)

When this method completes, the attachment is only marked for deletion; it is not actually deleted. The attachment object's editState property is set to AGSAttachmentEditStateMarkedForDeletion.

To completely delete the attachment, you need to post the edits to the server as described in the Committing changes to the server section in this topic. When the changes are successfully committed, the attachment is deleted both from the server and locally, and the attachment object's editState property is set to AGSAttachmentEditStateDeletedFromServer.

Committing changes to the server

When you add attachments or mark them for deletion, the attachment manager keeps track of the changes you make and holds on to them locally. If the application is closed or the device powers down, the changes will be lost. To persist the changes on the server, you need to invoke postLocalEditsToServer on AGSAttachmentManager.

//Only sync if the attachment manager contains local edits
if attMgr.hasLocalEdits() {
 attMgr.postLocalEditsToServer()
}

The postingLocalEdits property on AGSAttachmentManager is set while changes are being committed to the server. You can attach a key-value observer to this property to show an activity indicator to the user.

When the operation completes, the attachment manager's delegate is notified via the attachmentManager:didPostLocalEditsToServer: method.

If an error is encountered while posting the edits, the networkError or editResultError property on individual AGSAttachment objects is set depending on whether a network error prevented the operation from succeeding, or if an underlying database error occurred on the server. A delegate should always inspect these properties and handle errors appropriately.

func attachmentManager(attachmentManager: AGSAttachmentManager!, didPostLocalEditsToServer attachmentsPosted: [AnyObject]!) {
 //loop through all attachments looking for failures
 var _anyFailure = false
 for attachment in attachmentsPosted as [AGSAttachment] {
  if (attachment.networkError != nil) | (attachment.editResultError != nil) {
   _anyFailure = true
   var reason:String
   if attachment.networkError != nil {
    reason = attachment.networkError.localizedDescription
   }
   else if attachment.editResultError != nil {
    reason = attachment.editResultError.errorDescription
   }
   println("Attachment '\(attachment.attachmentInfo.name)' could not be synced with server because \(reason)")
  }
 }
        
 if _anyFailure {
  //warn the user
 }
}

To cancel an operation in progress, you can invoke cancelPostLocalEditsToServer. However, some edits may have already been committed to the server when you call this method. Those will not be cancelled. Only the uncommitted edits will be cancelled.

To undo local edits to the attachments that have not yet been posted, you can invoke cancelLocalEdits. This will revert the attachments to their original state before any attachments were added or marked for deletion.

See also

Feature layer editing sample using pop-ups.