我的AWS S3后端有一个存储桶,里面装满了我想加载到我的UICollectionViewCell上的图像。我应该采用什么方法来实现呢?我也在寻找最有效的方法。
我可能会注意到,目前在我的项目中,我拥有的框架是Alamofire,swiftyJSON和Haneke(用于缓存目的),虽然我不知道如何正确使用它们来实现我的目标。我还可以补充说我正在使用Parse.com作为我的BaaS,所以如果有一种方法可以将解析集成在其中,那么也会受到欢迎。
所有建议在Swift中?
答案 0 :(得分:2)
我建议的解决方案是使用Parse.com作为图书元数据的来源,使用s3作为存储。我认为您不需要任何其他组件(我特别怀疑基本iOS内容的网络代码便利包装)。
所以我会(并且确实证明它有效)设置这样的解析模型......
这里有一个swift中的vanilla ViewController,它有一个集合视图和一系列自定义swift" Book"对象...
// ViewController.swift
import UIKit
import Parse
class ViewController: UIViewController, UICollectionViewDataSource, UICollectionViewDelegate {
@IBOutlet weak private var collectionView : UICollectionView!
var books : Array<Book>!
override func viewDidLoad() {
super.viewDidLoad()
self.books = []
}
override func viewDidAppear(animated: Bool) {
super.viewDidAppear(animated)
self.loadBooks()
}
func loadBooks() {
var query = PFQuery(className: "Book")
query.findObjectsInBackgroundWithBlock { (objects: [AnyObject]?, error: NSError?) -> Void in
if error == nil {
let bookObjects = objects as! [PFObject]
for (index, object) in enumerate(bookObjects) {
self.books.append(Book(pfBook: object))
}
}
self.collectionView.reloadData()
}
}
基本的东西。当视图出现时,查询解析书籍对象,当它们被返回时,创建swift&#34; Book&#34;它们周围的包装器并重新加载集合视图。这是快速的图书班......
// Book.swift
import Parse
class Book: NSObject {
var pfBook : PFObject
var coverImage : UIImage!
init(pfBook: PFObject) {
self.pfBook = pfBook
}
func fetchCoverImage(completion: (image: UIImage?, error: NSError?) -> Void) {
let urlString = self.pfBook["coverUrl"] as! String
let url = NSURL(string: urlString)
let request = NSURLRequest(URL: url!)
let queue = dispatch_get_main_queue()
NSURLConnection.sendAsynchronousRequest(request, queue: NSOperationQueue.mainQueue()) { (response: NSURLResponse?, data: NSData?, error: NSError?) in
if error == nil {
self.coverImage = UIImage(data: data!)
completion(image: self.coverImage, error: nil)
} else {
completion(image: nil, error: error)
}
}
}
}
有趣的方法从保存在PFObject中的url中获取封面图像。 (查看parse.com数据浏览器中的url列。我在这里使用了一个快捷方式,并在网络上使用了一个很好的虚拟图像生成器。你需要实现一个具有相同签名的方法,但让它从s3获取图像)。
唯一剩下的就是集合视图数据源。再回到ViewController.swift ...
// ViewController.swift
func collectionView(collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return self.books.count
}
func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCellWithReuseIdentifier("Cell",
forIndexPath:indexPath) as! UICollectionViewCell
if cell.backgroundView == nil { // brand new cell
let v = UIImageView(frame:cell.bounds)
v.tag = 32
v.contentMode = .ScaleToFill
cell.backgroundView = v
}
let book = self.books[indexPath.row]
let coverImage = book.coverImage
if coverImage == nil {
book.fetchCoverImage({ (image, error) -> Void in
collectionView.reloadItemsAtIndexPaths([indexPath])
})
} else {
let imageView = cell.viewWithTag(32) as! UIImageView
imageView.image = book.coverImage
}
return cell
}
注意我们在cellForRow ...方法中做了什么:如果book对象有一个缓存的coverImage,我们将它放在图像视图中。否则,我们会告诉本书获取它的封面艺术,并在完成后,在当前索引路径重新加载单元格(我们不再依赖于单元格当前是正常的,因为时间过去而图像正在取出的)。
这就是跑步的样子......
答案 1 :(得分:0)
我正面临这个问题,并且有一个很好的解决方案,如何在单元格或其他视图中将图像从AWS S3加载到UIImageView
。为此,我还使用SDWebImage
SDK SDWebImage
因此,我们为UIImageView
创建一个扩展名并导入SDWebImage,然后将图像缓存添加到仅缓存图像链接中
import UIKit
import SDWebImage
let imageCache = NSCache<NSString, NSString>()
extension UIImageView {
func loadAsyncWithCacheFromAWSS3(_ link: String?, placeholder: UIImage? = UIImage(named: "placeholder")) {
guard let unwrappedlink = link else { return self.image = placeholder }
// Use your own image appearing style
self.sd_imageTransition = .fade
if !loadFromCache(unwrappedlink as NSString, placeholder: placeholder) {
let file = File(bucket: 'YOUR BUCKET', key: unwrappedlink, region: 'YOUR REGION')
AWSManager.shared.getFileURL(file: file) { [weak self] (string, url, error) in
guard let validURL = url else { self?.image = placeholder; return }
imageCache.setObject(NSString(string: validURL.absoluteString), forKey: NSString(string: unwrappedlink))
guard unwrappedlink == link else {
guard let key = link else { return }
self?.loadFromCashe(key as NSString, placeholder: placeholder)
return
}
self?.sd_setImage(with: validURL, placeholderImage: placeholder, options: [.scaleDownLargeImages])
}
}
}
// quick load from existing cashed link
@discardableResult
private func loadFromCache(_ key: NSString, placeholder: UIImage?) -> Bool {
guard let string = imageCache.object(forKey: key) else { return false }
let link = URL(string: String(string))
self.sd_setImage(with: link, placeholderImage: placeholder, options: [.scaleDownLargeImages])
return true
}
}
这是具有getFileURL
方法的单例类
func getFileURL(file: File, completionHandler: @escaping (String?, URL?, Error?) -> Void) {
let getPreSignedURLRequest = AWSS3GetPreSignedURLRequest()
getPreSignedURLRequest.bucket = file.bucket
getPreSignedURLRequest.key = file.key
getPreSignedURLRequest.httpMethod = .GET
getPreSignedURLRequest.expires = Date().adjust(hour: 24, minute: 0, second: 0)
getPreSignedURLRequest.minimumCredentialsExpirationInterval = 10
AWSS3PreSignedURLBuilder.s3PreSignedURLBuilder(forKey: 'YOUR BUILDER URL').getPreSignedURL(getPreSignedURLRequest).continueWith { (task: AWSTask<NSURL>) -> Any? in
if let error = task.error as NSError? {
completionHandler(nil, nil, error)
return nil
}
let presignedURL = task.result
completionHandler(file.key, presignedURL as URL?, nil)
return nil
}
}
在Appdelegate
的{{1}}简单调用func applicationDidReceiveMemoryWarning(_ application: UIApplication)