iOS CoreSpotlight Thumbnail Image from URL
Asked Answered
S

2

7

I'm trying to build a test app that uses CoreSpotlight to make content searchable in iOS Spotlight. Currently I have it setup to whenever the user taps a refresh button it makes a server request then deleteAllSearchableItems then indexSearchableItems (probably not the best way but easiest for right now, since I'm still in the beginning phases of figuring this out).

Below is my code that does that.

var searchableItems: [CSSearchableItem] = []
for i in 0 ..< self._ids.count {
    let attributeSet = CSSearchableItemAttributeSet(itemContentType: kUTTypeItem as String)

    attributeSet.title = self._titles[i]
    attributeSet.contentDescription = self._descriptions[i]

    let searchableItem = CSSearchableItem(uniqueIdentifier: self._ids[i], domainIdentifier: "com.domain.appname", attributeSet: attributeSet)

    searchableItems.append(searchableItem)
}

CSSearchableIndex.default().deleteAllSearchableItems(completionHandler: { (error) -> Void in
    CSSearchableIndex.default().indexSearchableItems(searchableItems) { (error) -> Void in
        if error != nil {
            print(error?.localizedDescription ?? "Error")
        }
    }
})

My next thing I'm trying to do is I have an array of images called self._images. Inside of that array is either an empty string ("") or a string of a URL ("https://mywebsite.com/image.png").

Currently I can use the code below to set the image of a UIImageView to the image at that URL, using AlamofireImage.

if (self._images[0] != "") {
    myImageView.af_setImage(withURL: URL(string: self._images[0])!)
}

How can I get that same image into the CoreSpotlight attributeSet?

I'm assuming attributeSet.thumbnailData.af_setImage(withURL: imagedownloadURL) won't work. Especially since it's async.

What would be the easiest way to integrate this?

I've tried a few things such as for loops and such but the biggest problem is the async and I can't seem to figure out a solution to do this since it's async and I have multiple items.

Thank you so much in advance!

Spacecraft answered 22/5, 2017 at 0:48 Comment(0)
G
6

Easiest solution but not the best one...

DispatchQueue.global(qos: .userInitiated).async {
    var searchableItems: [CSSearchableItem] = []
    for i in 0 ..< self._ids.count {
        let attributeSet = CSSearchableItemAttributeSet(itemContentType: kUTTypeItem as String)
        attributeSet.title = self._titles[i]
        attributeSet.contentDescription = self._descriptions[i]
        let searchableItem = CSSearchableItem(uniqueIdentifier: self._ids[i], domainIdentifier: "com.domain.appname", attributeSet: attributeSet)

        if let imageUrl = URL(string: self._images[i]) {
            let urlRequest = URLRequest.init(url: imageUrl)
            if let cashedImage = UIImageView.af_sharedImageDownloader.imageCache?.image(for: urlRequest, withIdentifier: nil) {
                if let data = UIImageJPEGRepresentation(cashedImage, 1.0) {
                    attributeSet.thumbnailData = data
                }
            } else {
                if let data = NSData.init(contentsOf: imageUrl) {
                    attributeSet.thumbnailData = data as Data
                    if let image = UIImage.init(data: data as Data) {
                        let urlRequest = URLRequest.init(url: imageUrl)
                        UIImageView.af_sharedImageDownloader.imageCache?.add(image, for: urlRequest, withIdentifier: nil)
                    }
                }
            }
        }
        searchableItems.append(searchableItem)
    }

    CSSearchableIndex.default().deleteAllSearchableItems(completionHandler: { (error) -> Void in
        CSSearchableIndex.default().indexSearchableItems(searchableItems) { (error) -> Void in
            if error != nil {
                print(error?.localizedDescription ?? "Error")
            }
        }
    })
}

Edited

Why not the good solution? To avoid async issue, I have just put everything in one async closure and doing the sync image downloading.

UPDATE

Added default Alamofire cashing, before downloading it first look's for the cashed image now.

Goop answered 26/5, 2017 at 6:51 Comment(3)
Can you please add a little bit more detail to your answer? How exactly does your code example work? And why is it not the best solution? Just overall more detail would be helpful.Spacecraft
That detail was helpful. I'm still trying to wrap my head around async vs sync in terms of Swift. I'm going to up vote your answer now. I don't award the bounty and I don't accept an answer until the bounty is over in case someone has a better answer or something like that. But I will award the bounty to some question and accept some answer after it's over. Thank you very much tho.Spacecraft
After testing this it seems to work but it does seem to be kinda slow. Or at least the first time it was kinda slow. Some of the items weren't showing up in Spotlight for a little bit. So if you happen to have a better solution for improving the performance of this that would be awesome. As I am using af_setImage and that doesn't seem to reload the image every time. Only the first time.Spacecraft
D
5

Here is a better solution using thumbnailURL or thumbnailData, since you have a cached images throw whetever alamofire, SDWebImage ...

it's simple and perfect performance wise

For thumbnailURL it accept only local paths:

  1. get the file path for the cached image
  2. create a URL object from the file path prefix with "file://"

"file://". to indicate it's local path

    if let path = SDImageCache.shared().defaultCachePath(forKey: item.url_thumbnail), let url = URL(string: "file://\(path)") {
        attributeSet.thumbnailURL = url
    }

For thumbnailData:

just assign the local url path

attributeSet.thumbnailData = try? Data(contentsOf: url)

to debug and getting know what is going on simply just

 do {
     attributeSet.thumbnailData = try Data(contentsOf: url)
 }catch (let error as NSError){
      print(error)
 }

just please note I am using SDWebImage to get the cached image's path, since I am using it to cache the photos

Delete answered 6/2, 2018 at 7:59 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.