I'm creating a search field to allow users to search for tags associated with a photo, and then only show photos containing that tag in my List. I'm using a computed property to check if my array of Photo
contains the tag but the tags are in a nested array several properties deep in my Photo
object. I need some help filtering the photos array from the computed property so my List uses the correct photos.
I'm trying to use this computed property to filter my photos:
struct PhotoListView: View {
let photos: [Photo]
@State private var searchText: String = ""
var filteredPhotos: [Photo] {
if searchText.count == 0 {
return photos
} else {
return photos.filter { photo in
return photo.info?.tags.tagContent.filter { $0._content.contains(searchText) }
}
}
}
var body: some View {
NavigationStack {
List {
ForEach(filteredPhotos) { photo in
NavigationLink {
PhotoDetailView(photo: photo)
} label: {
PhotoRow(photo: photo)
}
}
}
.navigationTitle("Recent Photos")
.searchable(text: $searchText)
}
}
}
The attempt above results in an error - Cannot convert value of type '[TagContent]?' to closure result type 'Bool'
class Photo: Decodable, Identifiable {
let id: String
let owner: String
let secret: String
let title: String
let server: String
let farm: Int
var imageURL: URL?
var info: PhotoInfo?
}
struct PhotoInfo: Decodable {
let id: String
let dateuploaded: String
let tags: PhotoTags
}
struct PhotoTags: Decodable {
let tagContent: [TagContent]
enum CodingKeys: String, CodingKey {
case tagContent = "tag"
}
}
struct TagContent: Decodable, Hashable {
let id: String
let _content: String
}
Using the above model structure can anyone help me filter the tags by _content
from my computed property?
CodePudding user response:
The filter function needs a boolean to determine if the value should be included. But for now you filter function returns only the inner filtered collection. Check if this collection contains any values.
return photos.filter { photo in
!(photo.info?.tags.tagContent.filter { $0._content.contains(searchText) }.isEmpty ?? true)
}
CodePudding user response:
Currently your return [TagContent]
rather than Bool
Replace filteredPhotos
with:
var filteredPhotos: [Photo] {
if searchText.count == 0 {
return photos
} else {
return photos.filter { photo in
let tagContents = photo.info?.tags.tagContent.filter{ $0._content.contains(searchText) } ?? []
return !tagContents.isEmpty
}
}
}