Привет всем! Я анализирую следующие значения JSON
и UITableView
, используя UITableViewDiffableDataSource
для хорошей анимации поиска.
JSON: https://www.pathofexile.com/api/trade/data/items
А вот репо: https://github.com/laurentdelorme/PathOfData
Из JSON, Я могу загрузить все 13 различных категорий, как показано в файле модели. Затем я могу скопировать sh данные из этих категорий в другой tableView (тот, который использует UITableViewDiffableDataSource
) и отобразить все мило.
Однако есть ОДНА категория, в которой мое приложение делает sh, когда я пытаюсь передать sh его содержимое в DetailViewController, который является категорией «Карты» в начальном ViewController
.
Вот моя модель:
struct ItemCategories: Codable {
var result: [ItemCategory]
}
struct ItemCategory: Codable {
var label: String
var entries: [Item]
}
struct Item: Codable, Hashable {
var name: String?
var type: String?
var text: String?
}
Вот мой ViewController:
import UIKit
class ViewController: UITableViewController {
let urlString = "https://www.pathofexile.com/api/trade/data/items"
var categories = [ItemCategory]()
override func viewDidLoad() {
super.viewDidLoad()
title = "Path of Data"
navigationController?.navigationBar.prefersLargeTitles = true
parseJSON()
for family: String in UIFont.familyNames
{
print(family)
for names: String in UIFont.fontNames(forFamilyName: family)
{
print("== \(names)")
}
}
}
func parseJSON() {
guard let url = URL(string: urlString) else { return }
guard let data = try? Data(contentsOf: url) else { return }
let decoder = JSONDecoder()
guard let jsonItemCategories = try? decoder.decode(ItemCategories.self, from: data) else { return }
categories = jsonItemCategories.result
tableView.reloadData()
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return categories.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath)
var categoryName = categories[indexPath.row].label
if categoryName == "" { categoryName = "Unknown" }
cell.textLabel?.text = categoryName
let font = UIFont(name: "Fontin-SmallCaps", size: 30)
cell.textLabel?.font = font
cell.textLabel?.textColor = .systemOrange
let numberOfItemsInCategory = String(categories[indexPath.row].entries.count)
cell.detailTextLabel?.text = numberOfItemsInCategory + " items"
return cell
}
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
if let vc = storyboard?.instantiateViewController(identifier: "Detail") as? DetailViewController {
let listLabel: String? = categories[indexPath.row].label
vc.title = listLabel
let itemList = categories[indexPath.row].entries
vc.items = itemList
print(itemList)
vc.category = categories[indexPath.row].label
navigationController?.pushViewController(vc, animated: true)
}
}
}
Вот DetailViewController:
import UIKit
import SafariServices
class DetailViewController: UITableViewController {
enum Section {
case main
}
var category: String!
var items: [Item] = []
var transformedItems: [Item] = []
var filteredItems: [Item] = []
var isSearching: Bool = false
var dataSource: UITableViewDiffableDataSource<Section,Item>!
override func viewDidLoad() {
super.viewDidLoad()
navigationController?.navigationBar.prefersLargeTitles = true
navigationController?.navigationBar.tintColor = .systemOrange
replacenNilNameFor(items: items)
configureDataSource()
updateData(on: items)
congifureSearchController()
}
func replacenNilNameFor(items: [Item]) {
for item in items {
if item.name == nil {
guard item.type != nil else { return }
let newItem = Item(name: item.type, type: nil, text: nil)
transformedItems.append(newItem)
} else {
transformedItems.append(item)
}
}
self.items = transformedItems
}
func configureDataSource() {
dataSource = UITableViewDiffableDataSource<Section, Item>(tableView: self.tableView, cellProvider: { tableView, indexPath, item -> UITableViewCell? in
let cell = tableView.dequeueReusableCell(withIdentifier: "Detail", for: indexPath)
cell.textLabel?.text = item.name
cell.detailTextLabel?.text = item.type
let font = UIFont(name: "Fontin-SmallCaps", size: 25)
cell.textLabel?.font = font
cell.textLabel?.textColor = self.setLabelColor(for: self.category)
return cell
})
}
func setLabelColor(for category: String) -> UIColor {
switch category {
case "Prophecies":
return UIColor(red: 0.6471, green: 0.1569, blue: 0.7569, alpha: 1.0)
default:
return UIColor(red: 0.6392, green: 0.549, blue: 0.4275, alpha: 1.0)
}
}
func updateData(on items: [Item]) {
var snapshot = NSDiffableDataSourceSnapshot<Section, Item>()
snapshot.appendSections([.main])
snapshot.appendItems(items)
dataSource.apply(snapshot, animatingDifferences: true)
}
func congifureSearchController() {
let searchController = UISearchController()
searchController.searchResultsUpdater = self
searchController.searchBar.placeholder = "Search for an item"
searchController.searchBar.delegate = self
navigationItem.searchController = searchController
}
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let endpoint = "https://pathofexile.gamepedia.com/"
let activeArray = isSearching ? filteredItems : items
let item = activeArray[indexPath.row]
let url = URL(string: endpoint + formatNameFor(item: item))
let sf = SFSafariViewController(url: url!)
present(sf, animated: true)
}
func formatNameFor(item: Item) -> String {
let name = item.name!
let firstChange = name.replacingOccurrences(of: " ", with: "_")
let secondChange = firstChange.replacingOccurrences(of: "'", with: "%27")
return secondChange
}
}
extension DetailViewController: UISearchResultsUpdating, UISearchBarDelegate {
func updateSearchResults(for searchController: UISearchController) {
guard let filter = searchController.searchBar.text, !filter.isEmpty else { return }
isSearching = true
filteredItems = items.filter { ($0.name?.lowercased().contains(filter.lowercased()))! }
updateData(on: filteredItems)
}
func searchBarCancelButtonClicked(_ searchBar: UISearchBar) {
isSearching = false
updateData(on: items)
}
}
И вот сообщение об ошибке, которое я получаю когда я пытаюсь войти в категорию «Карты»:
2020-02-28 14:40:20.470098+0100 PathOfData[2789:224548] *** Assertion failure in -[_UIDiffableDataSourceUpdate initWithIdentifiers:sectionIdentifiers:action:desinationIdentifier:relativePosition:destinationIsSection:], /BuildRoot/Library/Caches/com.apple.xbs/Sources/UIKitCore_Sim/UIKit-3901.4.2/_UIDiffableDataSource.m:1417
2020-02-28 14:40:20.474313+0100 PathOfData[2789:224548] *** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'Fatal: supplied identifiers are not unique.'
*** First throw call stack:
(
0 CoreFoundation 0x00000001069f327e __exceptionPreprocess + 350
1 libobjc.A.dylib 0x0000000105077b20 objc_exception_throw + 48
2 CoreFoundation 0x00000001069f2ff8 +[NSException raise:format:arguments:] + 88
3 Foundation 0x0000000104a9fb51 -[NSAssertionHandler handleFailureInMethod:object:file:lineNumber:description:] + 191
4 UIKitCore 0x0000000119c4dcdf -[_UIDiffableDataSourceUpdate initWithIdentifiers:sectionIdentifiers:action:desinationIdentifier:relativePosition:destinationIsSection:] + 725
5 UIKitCore 0x0000000119c4e04e -[_UIDiffableDataSourceUpdate initWithItemIdentifiers:appendingToDestinationSectionIdentifier:] + 90
6 UIKitCore 0x0000000119c43408 -[__UIDiffableDataSource appendItemsWithIdentifiers:intoSectionWithIdentifier:] + 165
7 libswiftUIKit.dylib 0x0000000105e9f061 $s5UIKit28NSDiffableDataSourceSnapshotV11appendItems_9toSectionySayq_G_xSgtF + 241
8 PathOfData 0x0000000104723b41 $s10PathOfData20DetailViewControllerC06updateC02onySayAA4ItemVG_tF + 369
9 PathOfData 0x000000010472231f $s10PathOfData20DetailViewControllerC11viewDidLoadyyF + 767
10 PathOfData 0x00000001047223db $s10PathOfData20DetailViewControllerC11viewDidLoadyyFTo + 43
11 UIKitCore 0x0000000119e22f01 -[UIViewController _sendViewDidLoadWithAppearanceProxyObjectTaggingEnabled] + 83
12 UIKitCore 0x0000000119e27e5a -[UIViewController loadViewIfRequired] + 1084
13 UIKitCore 0x0000000119e28277 -[UIViewController view] + 27
14 UIKitCore 0x0000000119d773dd -[UINavigationController _startCustomTransition:] + 1039
15 UIKitCore 0x0000000119d8d30c -[UINavigationController _startDeferredTransitionIfNeeded:] + 698
16 UIKitCore 0x0000000119d8e721 -[UINavigationController __viewWillLayoutSubviews] + 150
17 UIKitCore 0x0000000119d6f553 -[UILayoutContainerView layoutSubviews] + 217
18 UIKitCore 0x000000011a98c4bd -[UIView(CALayerDelegate) layoutSublayersOfLayer:] + 2478
19 QuartzCore 0x000000010bbe7db1 -[CALayer layoutSublayers] + 255
20 QuartzCore 0x000000010bbedfa3 _ZN2CA5Layer16layout_if_neededEPNS_11TransactionE + 517
21 QuartzCore 0x000000010bbf98da _ZN2CA5Layer28layout_and_display_if_neededEPNS_11TransactionE + 80
22 QuartzCore 0x000000010bb40848 _ZN2CA7Context18commit_transactionEPNS_11TransactionEd + 324
23 QuartzCore 0x000000010bb75b51 _ZN2CA11Transaction6commitEv + 643
24 UIKitCore 0x000000011a4d03f4 _afterCACommitHandler + 160
25 CoreFoundation 0x0000000106955867 __CFRUNLOOP_IS_CALLING_OUT_TO_AN_OBSERVER_CALLBACK_FUNCTION__ + 23
26 CoreFoundation 0x00000001069502fe __CFRunLoopDoObservers + 430
27 CoreFoundation 0x000000010695097a __CFRunLoopRun + 1514
28 CoreFoundation 0x0000000106950066 CFRunLoopRunSpecific + 438
29 GraphicsServices 0x0000000109100bb0 GSEventRunModal + 65
30 UIKitCore 0x000000011a4a6d4d UIApplicationMain + 1621
31 PathOfData 0x000000010471fe6b main + 75
32 libdyld.dylib 0x00000001078c5c25 start + 1
)
libc++abi.dylib: terminating with uncaught exception of type NSException
(lldb)
Я не могу понять, что здесь происходит, поэтому, если у кого-то есть идея, это было бы здорово ?
Спасибо тебе очень нравится!