Is this possible without SwiftyJSON or other frameworks? Im trying to understand if keyDecodingStrategy is the solution, or if there is another.
let fileManager = FileManager.default
let documentsURL = fileManager.urls(for: .documentDirectory, in: .userDomainMask)[0]
do {
let fileURLs = try fileManager.contentsOfDirectory(at: documentsURL, includingPropertiesForKeys: nil)
for url in fileURLs {
print(url) // <- that is the place for processing the urls
let data = try Data(contentsOf: url)
print(data)
}
}
} catch {
print("Error while enumerating files \(documentsURL.path): \(error.localizedDescription)")
}
If I'm understanding your question correctly, It should certainly be possible to use JSONDecoder to do this.
You can write a struct that only includes the key you actually care about extracting. For example, if I had a bunch of JSON files, each one formatted like this:
{"someStringField": "x", "someIntField": 1}
And I only wanted to collect the "someStringField" values, I could write a Decodablestruct that looks like this:
struct MyJSONData: Decodable {
let someStringField: String
}
I can get a specific instance and the desired field with
let s = try JSONDecoder().decode(MyJSONData.self, from: data)
let str = s.someStringField
The decoder only cares that all the properties of MyJSONData are present in the data. It does not care if all of the key/value pairs in the data are present in MyJSONData.
Thanks for your answer, but in my case it is not working well.
**Error loading data from disk keyNotFound(CodingKeys(stringValue: "type", intValue: nil), Swift.DecodingError.Context(codingPath: [_JSONKey(stringValue: "Index 0", intValue: 0)], debugDescription: "No value associated with key CodingKeys(stringValue: \"type\", intValue: nil) (\"type\").", underlyingError: nil))**
There are multiple playlists and want I want to archive is to get the type of the objects from all playlists.
Right now I'm able to get the type of objects from a selected playlist at a time by using this code:
class Playlist: Equatable, Codable {
init(name: String, objects: [Object] = []) {
self.name = name
self.objects = objects
}
// MARK: Properties
let name: String
var objects: [Object]
}
func fileURL() -> URL {
let paths = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)
let documentsDirectory = paths[0]
let filename = "playlists.json"
let fullURL = documentsDirectory.appendingPathComponent(filename)
return fullURL
}
func loadFromPersistentStore() -> [Playlist] {
do {
let data = try Data(contentsOf: fileURL())
let jd = JSONDecoder()
let playlists = try jd.decode([Playlist].self, from: data)
return playlists
} catch let error {
print("Error loading data from disk \(error)")
}
return []
}
what does your implementation of Object look like? Should be something like this:
class Object: Decodable {
let type: String // or an enum? see below - let type: ObjectType
// ... and other properties
}
enum ObjectType: String, Decodable {
case liveChannel = "LiveChannel"
// and so on...
}
class Object: Equatable, Codable {
enum Group: String, Codable {
case LiveChannel
case TelevisionShow
case Movie
case unsupported
static let allGroups: [Group] = [.LiveChannel, .TelevisionShow, .Movie, .unsupported]
}
init(type: Group.RawValue, title: String, group: String, url: String, logo: String) {
self.type = type
self.title = title
self.group = group
self.url = url
self.logo = logo
}
// MARK: Properties
let type: String
let title: String
let group: String
let url: String
let logo: String
}
The problem is that I can just get info from one playlist at a time: staticfunc objectsByType(playList: Playlist, type: Group) -> [Object] {
This will return an array of all the objects in the playlist matching a type with that rawValue. You can then iterate over that array and use these Objects however you like. I'm sorry, I think I'm having trouble understanding what you're trying to accomplish.
Yes, it returns all objects from one selected playlist, but the Json file contains few playlists. The goal is to return all objects from all playlists.
Sorry, I'm on the road so I may have a few typos. But what you have is almost there. You need a function that takes an array of playlists and collects all objects that contain that particular type.
func objectsByType(playLists: [Playlist], type: Object.Group) -> [Object] {
var found: [Object] = []
for list in playLists {
let objectsMatchingType = list.objects.filter { $0.type == type.rawValue }
found.append(contentsOf: objectsMatchingType)
}
return found
}
func objectsByType(playLists: [Playlist], type: Object.Group) -> [Object] {
return playLists
.flatMap { $0.objects } // gives me an array of all objects from all playlists
.filter { $0.type == type.rawValue } // filter it to get the type you look for
}