Today I upgraded Xcode 6 to beta 5 (from beta 1) and as you can imagine I found my previously perfectly working Swift app full of errors of all kind (well, a lot changed from beta 1). Of all errors, there is one I just can't figure out how to fix. It's related to swift closures, in particular the enumerationBlock argument of the .enumerateGroupsWithTypes method. Here is the code:
assetLib.enumerateGroupsWithTypes(ALAssetsGroupType(ALAssetsGroupSavedPhotos), usingBlock: {
(group: ALAssetsGroup?, stop: CMutablePointer<ObjCBool>) in
...
}, failureBlock: {
(error: NSError!) in
...
})
This did work perfectly in Swift (Xcode 6 beta 1). But now, I get 2 errors:
" 'UnsafeMutablePointer' is not a subtype of 'error type' "
" Use of undeclared type 'CMutablePointer' "
It was clear that CMutablePointer did not exist anymore, so I tried to modify the stop argument like:
..., stop: UnsafeMutablePointer<ObjCBool> ...
After this change, the second error obviously disappeared, but the first transformed in:
" Could not find an overload for 'init' that accepts the supplied arguments "
I even tried to change the UnsafeMutablePointer to a UnsafePointer, as suggested from this post.
EDIT:
Here is the full code of the enumerateGroupsWithTypes method:
assetLib.enumerateGroupsWithTypes(ALAssetsGroupType(ALAssetsGroupSavedPhotos), usingBlock: {
(group: ALAssetsGroup?, stop: UnsafeMutablePointer<ObjCBool>) in
if group != nil {
group!.setAssetsFilter(ALAssetsFilter.allPhotos())
group!.enumerateAssetsAtIndexes(NSIndexSet(index: group!.numberOfAssets()-1), options: nil, usingBlock: {
(result: ALAsset!, index: Int, stop: UnsafeMutablePointer<ObjCBool>) in
if result {
var alAssetRapresentation: ALAssetRepresentation = result.defaultRepresentation()
url = alAssetRapresentation.url()
}
})
}
else if group == nil {
assetLib.assetForURL(url, resultBlock: {
(asset: ALAsset!) in
if asset != nil {
var assetRep: ALAssetRepresentation = asset.defaultRepresentation()
var iref = assetRep.fullResolutionImage().takeUnretainedValue()
var image = UIImage(CGImage: iref)
imageView.image = image
self.view.addSubview(imageView)
let mask = CAShapeLayer()
mask.path = UIBezierPath(ovalInRect: CGRectMake(0, 0, 200, 200)).CGPath
mask.frame = CGPathGetPathBoundingBox(mask.path)
mapView.layer.mask = mask
self.view.addSubview(mapView)
}
}, failureBlock: {
(error: NSError!) in
NSLog("Error!", nil)
})
}
}, failureBlock: {
(error: NSError!) in
NSLog("Error!", nil)
})
Here is a for me working example: This code looks for the album „projectname“ and safe the image „in“ this album. If the album do not exists, the album will be created.
Attention: If there WAS an album with the SAME name. You can NOT create a album with this name once again. You must use a new name. In this example the projectname will extent with date and time.
By the way, Apples apps could create a album with the same name.
func saveImage(projectName : String) { // Return a new projectname
// in the var self.newProjectName if the old one could not created
if self.isSaved { // was here bevor
return
}
let library = ALAssetsLibrary() // This object will provide the access to to the library
// List over all groups in the PhotoDirectory
// ALAssetsGroupAll is the key to select the listed groups
// possible change to type:Album
library.enumerateGroupsWithTypes(ALAssetsGroupType(ALAssetsGroupAll),
usingBlock: {(group : ALAssetsGroup!, stop : UnsafeMutablePointer<ObjCBool>) in
if group != nil { // The listing of the directory content has found an object
// Did we search for this album?
if group.valueForProperty(ALAssetsGroupPropertyName).isEqualToString(projectName) {
stop.initialize(true) // Stop the enumeration thread
library.writeImageToSavedPhotosAlbum(self.cgImage, metadata: self.ciImage?.properties(),
completionBlock: {(assetUrl, error: NSError?) -> Void in
if let theError = error?.code {
lapApp.logger.addLog("saved image failed, first try \(error?.localizedDescription) code \(theError)")
} else {
library.assetForURL(assetUrl,
resultBlock: { (asset: ALAsset!) -> Void in
group.addAsset(asset)
self.isSaved = true
return // Stop this process and leave
}, failureBlock: {
(theError: NSError!) -> Void in
lapApp.logger.addLog("error occurred, image to album at the first try: \(theError.localizedDescription) ")
})
}
})
return // write image to the found album
} else {
// Album not found, enumeration will continue
}
}
else { // The album was not found, so we will create an album
if stop.memory.boolValue { // The enumeration will go over the end of the list. The stop-signal comes some time to late?
return
}
library.addAssetsGroupAlbumWithName(projectName,
resultBlock: {(group: ALAssetsGroup?) -> Void in
if let thegroup = group { // Check for a name conflict, possible was a album with the same name deleted. IOS8 will not create this album!
// The album was correct created, now we will add the picture to the album
library.writeImageToSavedPhotosAlbum(self.cgImage, metadata: self.ciImage?.properties(), completionBlock: {
(assetUrl, error: NSError?) -> Void in
if let theError = error?.code {
lapApp.logger.addLog("save image in new album failed. \(error?.localizedDescription) code \(theError)")
} else {
library.assetForURL(assetUrl,
resultBlock: { (asset: ALAsset!) -> Void in
thegroup.addAsset(asset)
self.isSaved = true
stop.initialize(true) // Stop the enumeration thread
return
}, failureBlock: {
(theError: NSError?) -> Void in
lapApp.logger.addLog("error occurred: \(theError?.localizedDescription)")
})
}
})
return
} else { // Name conflic with a deleted album.
// Work around: Create the Album with the Projectname an extend the name with Date and time
let formatter : NSDateFormatter = NSDateFormatter()
formatter.dateFormat = "yy.MM.dd hh:mm:ss"
let extensionDate = formatter.stringFromDate(NSDate())
self.newProjectName = projectName + " " + extensionDate // This is the new projectname
library.addAssetsGroupAlbumWithName(self.newProjectName,
resultBlock: {(group: ALAssetsGroup?) -> Void in
if let theGroup = group {
library.writeImageToSavedPhotosAlbum(self.cgImage, metadata: self.ciImage?.properties(), completionBlock: {
(assetUrl, error: NSError?) -> Void in
if let theError = error {
lapApp.logger.addLog("save image with new album name failed. \(error?.localizedDescription) code \(theError) \(self.newProjectName)")
} else {
library.assetForURL(assetUrl, resultBlock: { (asset: ALAsset!) -> Void in
theGroup.addAsset(asset)
self.isSaved = true
stop.initialize(true) // Stop the enumeration thread
return
}, failureBlock: {
(theError: NSError?) -> Void in
lapApp.logger.addLog("error at write image in new album occurred: \(theError?.localizedDescription)")
})
}
})
} else {
lapApp.logger.addLog("Problem adding albums with the name \(self.newProjectName)")
}
},
failureBlock: {
(error:NSError?) -> Void in
lapApp.logger.addLog("Problem adding albums: \(error)")
})
}
},
failureBlock: {
(error:NSError?) -> Void in
lapApp.logger.addLog("Problem loading albums: \(error)")
})
}
}, failureBlock: { (error:NSError?) in lapApp.logger.addLog("Problem loading albums: \(error)") })
} // End SaveImage
NSLog("Error!", nil) is wrong and should be NSLog("Error!").
(This seems to confuse the Swift compiler and causes unrelated error messages.)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With