Swift中是否存在更好的解决方案来处理这个api问题



我的原始json数据可能会误导您。键数组并不总是与其在同一索引处的值匹配。所以我重写了我的数据以反映我的意图。

假设我们有一个表视图来显示带有json:的歌曲

{
"albums": [
{
"title": "A",
"id": "174172",
"artistName": "Person X"
},
{
"title": "B",
"id": "19201827",
"artistName": "Person Y"
},
{
"title": "C",
"id": "1927",
"artistName": "Person Z"
}
],
"songs": [
{
"name": "Song A",
"albumName": "A",
"albumId": "174172",
"duration": 180
},
{
"name": "Song B",
"albumName": "A",
"albumId": "174172",
"duration": 200
},
{
"name": "Song C",
"albumName": "B",
"albumId": "19201827",
"duration": 216
},
{
"name": "Song D",
"albumName": "C",
"albumId": "1927",
"duration": 216
}
]
}

我的模式如下:

struct Album: Decodable {
let title: String
let id: String
let artistName: String
}
struct Song: Decodable {
let name: String
let albumName: String
let albumId: String
let duration: Int
}

视图控制器伪代码如下:

class ViewController: UIViewController {
var songs: [Song] = []
var albums: [Album] = []
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return songs.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableview.dequeueReusableCell(withIdentifier: "SongCell", for: indexPath) as! SongCell
let song = songs[indexPath.row]
let album = albums.first { $0.id == song.albumId }
cell.updateUI(withSong: song, album: album)
return cell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let song = songs[indexPath.row]
let album = albums.first { $0.id == song.albumId }
pushDetailSongViewController(song, album)
}
func pushDetailSongViewController(_ song: Song, _ album: Album?) {
}
}

当我们有太多的歌曲和专辑时,let album = albums.first { $0.id == song.albumId }是一个有严重性能问题的地方。

那么,我们应该在这里使用什么数据结构来处理性能更新呢?

解析完键和值后,可以将这两个数组组合到一个字典中,然后将表视图的数据源作为该字典。

首先,使您的Song结构符合Hashable协议:

struct Song: Hashable {

为专辑和歌曲创建一个数组:

var albums: [Album] = []
var songs:  [Song]  = []

然后,将songs数组简化为字典,如下所示:

let data = songs.reduce([Album: Song]()) { (result, song) -> [Album: Song] in
guard let album = albums.first(where: { $0.id == song.albumID }) else { return result }
return result.merging([album: song], uniquingKeysWith: { (first, _) in first })
}

我用两个演示阵列测试了这一点:

let albums = [Album(id: "1",     name: "one"), Album(id: "2",     name: "two"), Album(id: "3",     name: "three")]
let songs  = [Song(albumID: "1", name: "ONE"), Song(albumID: "2", name: "TWO"), Song(albumID: "3", name: "THREE")]

这些将data变成:

[
<Album id: "1", name: "one">  : <Song albumID: "1", name: "ONE">,
<Album id: "2", name: "two">  : <Song albumID: "2", name: "TWO">,
<Album id: "3", name: "three">: <Song albumID: "3", name: "THREE">
]

额外信贷

如果你想要每张专辑的所有歌曲,你必须制作data[Album: [Song]]:

let data = albums.reduce([Album: [Song]]()) { (result, album) -> [Album: [Song]] in
let _songs = songs.filter({ $0.albumID == album.id })
guard !_songs.isEmpty else { return result }
return result.merging([album: _songs], uniquingKeysWith: { (first, _) in first })
}

具有以下阵列:

let albums = [Album(id: "1",     name: "one"), Album(id: "2",     name: "two"), Album(id: "3",     name: "three")]
let songs  = [Song(albumID: "1", name: "ONE"), Song(albumID: "2", name: "TWO"), Song(albumID: "3", name: "THREE"),
Song(albumID: "1", name: "ONE-1"), Song(albumID: "1", name: "ONE-2"), Song(albumID: "3", name: "THREE-1")]

你会得到:

[
<Album name: three, id: 3>: [
<Song name: THREE, albumID: 3>
<Song name: THREE-1, albumID: 3>
], 
<Album name: one, id: 1>: [
<Song name: ONE, albumID: 1>, 
<Song name: ONE-1, albumID: 1>, 
<Song name: ONE-2, albumID: 1>
],
<Album name: two, id: 2>: [
<Song name: TWO, albumID: 2>
]
]

JSON解析完成后,您应该创建一个struct,如下所示。

struct DataSet {
let id: String
let name: String
let value: String
}

此外,看看您的json,KeyValue数组的同一索引中的对象似乎与idkey相同。因此,在组合这两个数组时,如果迭代一个数组,您将知道另一个数组(O(1)(的索引。因此合并的时间复杂度将为CCD_ 15。

如果您不想更改太多,也许mapDictionary会有所帮助:

let keyMaps =  [String : String](uniqueKeysWithValues: keys.map{($0.id, $0.name)})
keyNamesInSequenceSameWithValues =  values.map{ keyMaps[$0.key]! )

最新更新