尝试将 Unsplash 中的图片显示到 UICollectionView 中
Trying to show pictures from Unsplash into a UICollectionView
我正在尝试显示一些使用 UICollectionView 从 Unsplash 获取的图片。这个想法是显示一个带有图像和作者姓名的单元格。
目前我只能显示单元格的边框和作者姓名,无论我如何处理无法显示 UIImage 的问题。
我在各处都添加了打印输出(是的,我提到过我是初学者...)并且我可以打印 url 字符串和对图像对象的引用。
我想知道我在 UIImageView 中显示 UIImage 的方式是否有问题,如果出于某种原因在绘制 View 时 UIImage 尚未准备好(我知道我必须获取它,为什么我可以打印它?)。
这是我的代码:
ViewController.swift
import UIKit
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .systemBackground
view.addSubview(titleView)
view.addSubview(searchBarView)
view.addSubview(collectionView)
searchBarView.delegate = self
collectionView.delegate = self
collectionView.dataSource = self
picsManager.delegate = self
setupLayout()
}
var picsManager = PicsManager()
var pics = PicsModel()
func setupLayout() {
NSLayoutConstraint.activate([
titleView.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor),
titleView.leadingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.leadingAnchor),
titleView.trailingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.trailingAnchor),
titleView.widthAnchor.constraint(equalTo: view.widthAnchor),
searchBarView.topAnchor.constraint(equalTo: titleView.bottomAnchor, constant: 10),
searchBarView.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 20),
searchBarView.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -20),
// collectionView.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor),
collectionView.topAnchor.constraint(equalTo: searchBarView.bottomAnchor),
collectionView.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor),
collectionView.leadingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.leadingAnchor),
collectionView.trailingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.trailingAnchor)
])
}
let titleView: UILabel = {
let tv = UILabel()
tv.translatesAutoresizingMaskIntoConstraints = false
// tv.font = UIFont.preferredFont(forTextStyle: .largeTitle)
tv.font = UIFont(name: "Georgia-Italic", size: 44)
tv.textColor = .systemBlue
tv.textAlignment = .center
tv.text = "Coins Live"
tv.sizeToFit()
return tv
}()
let searchBarView: UISearchBar = {
let sb = UISearchBar()
sb.translatesAutoresizingMaskIntoConstraints = false
sb.searchBarStyle = .default
sb.placeholder = "Search..."
sb.sizeToFit()
sb.isTranslucent = false
sb.showsCancelButton = false
return sb
}()
lazy var collectionView: UICollectionView = {
let layout = UICollectionViewFlowLayout()
layout.sectionInset = UIEdgeInsets(top: 0,
left: 10,
bottom: 0,
right: 10)
layout.minimumInteritemSpacing = 10
layout.minimumLineSpacing = 10
layout.scrollDirection = .vertical
let cv = UICollectionView(frame: .zero, collectionViewLayout: layout)
cv.backgroundColor = .systemYellow
cv.translatesAutoresizingMaskIntoConstraints = false
cv.register(CollectionViewCell.self, forCellWithReuseIdentifier: "CollectionViewCell")
return cv
}()
}
//MARK: - Extension UICollectionView
extension ViewController: UICollectionViewDelegateFlowLayout, UICollectionViewDelegate, UICollectionViewDataSource {
// Dimensions of the cell
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
// return CGSize(width: collectionView.frame.width / 3.5, height: collectionView.frame.width / 3.5)
return CGSize(width: collectionView.frame.width / 1.1, height: collectionView.frame.width / 1.1)
}
// How many cells
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return pics.pics.count
}
// Details of each cell
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "CollectionViewCell", for: indexPath) as! CollectionViewCell
cell.picLabel.text = pics.pics[indexPath.item].getUserName
// METHOD ONE
// let url = URL(string: pics.pics[indexPath.item].smallPicUrl)!
// let data = try? Data(contentsOf: url)
// let img = UIImage(data: data!)
// cell.backgroundImageView.image = img
// METHOD TWO
// let task = URLSession.shared.dataTask(with: url, completionHandler: { data, response, error in
// if error != nil {
// print("Error")
// return
// }
//
// if let data = data {
// DispatchQueue.main.async {
// cell.backgroundImageView = UIImageView(image: UIImage(data: data))
// print("cellForItemAt \(indexPath.item) : \(self.pics.pics[indexPath.item].smallPicUrl)")
// }
// }
// })
//
// task.resume()
// METHOD THREE
let urlString = pics.pics[indexPath.item].smallPicUrl
cell.configure(with: urlString)
return cell
}
}
extension ViewController: UISearchBarDelegate {
// Contents of the searchBar are sent, but only after a delay. This is to prevent sending
// a request after every character. Better to wait until the user has finished typing.
func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) {
NSObject.cancelPreviousPerformRequests(withTarget: self, selector: #selector(self.reload(_:)), object: searchBar)
perform(#selector(self.reload(_:)), with: searchBar, afterDelay: 0.5)
}
@objc func reload(_ searchBar: UISearchBar) {
guard let query = searchBar.text, query.trimmingCharacters(in: .whitespaces) != "" else {
print("nothing to search")
return
}
if let term = searchBar.searchTextField.text {
picsManager.getPics(term)
} else {
print("Invalid query.")
}
}
}
extension ViewController: PicsManagerDelegate {
func didUpdatePics(_ pics: PicsModel) {
DispatchQueue.main.async {
self.pics = pics
self.collectionView.reloadData()
// print("~~~ ~~~ ~~~ ~~~ ~~~ ~~~")
// print(pics.pics[0].smallPicUrl)
}
}
}
CollectionViewCell.swift
//
// CollectionViewCell.swift
// UIKit_ProgrammaticUI_SearchBar
//
// Created by Matteo on 31/08/2021.
//
import UIKit
class CollectionViewCell: UICollectionViewCell {
//MARK: - Init
override init(frame: CGRect) {
super.init(frame: frame)
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override func layoutSubviews() {
setupLayout()
}
//MARK: - Properties
lazy var roundedBackgroundView: UIView = {
let view = UIView()
view.translatesAutoresizingMaskIntoConstraints = false
view.layer.cornerRadius = 10
view.layer.borderWidth = 2
view.layer.borderColor = UIColor.systemTeal.cgColor
return view
}()
lazy var picLabel: UILabel = {
let label = UILabel()
label.translatesAutoresizingMaskIntoConstraints = false
label.font = UIFont(name: "HelveticaNeue", size: 13)
label.textColor = .systemIndigo
return label
}()
lazy var backgroundImageView: UIImageView = {
let iv = UIImageView()
iv.translatesAutoresizingMaskIntoConstraints = false
iv.layer.cornerRadius = 10
iv.layer.borderWidth = 2
iv.layer.borderColor = UIColor.systemTeal.cgColor
return iv
}()
}
//MARK: - Layout
extension CollectionViewCell {
private func setupLayout() {
// When configuring a view, you add any custom subview to self.contentView
// Option + leftClick for more info!
self.contentView.addSubview(roundedBackgroundView)
roundedBackgroundView.addSubview(picLabel)
NSLayoutConstraint.activate([
roundedBackgroundView.topAnchor.constraint(equalTo: self.contentView.topAnchor, constant: 5),
roundedBackgroundView.bottomAnchor.constraint(equalTo: self.contentView.bottomAnchor, constant: -5),
roundedBackgroundView.leadingAnchor.constraint(equalTo: self.contentView.leadingAnchor, constant: 5),
roundedBackgroundView.trailingAnchor.constraint(equalTo: self.contentView.trailingAnchor, constant: -5),
picLabel.centerXAnchor.constraint(equalTo: self.contentView.centerXAnchor),
picLabel.centerYAnchor.constraint(equalTo: self.contentView.bottomAnchor, constant: -15)
])
}
func configure(with urlString: String) {
guard let url = URL(string: urlString) else { return }
URLSession.shared.dataTask(with: url, completionHandler: { [weak self] data, _, error in
guard let data = data, error == nil else { return }
DispatchQueue.main.async {
let image = UIImage(data: data)
self!.backgroundImageView.image = image
print("~~~~~ ~~~~~ ~~~~~")
print(self?.backgroundImageView.image ?? "nothing to print here...")
}
}).resume()
}
}
PicsManager.swift
//
// PicsManager.swift
// UIKit_ProgrammaticUI_SearchBar
//
// Created by Matteo on 01/09/2021.
//
import Foundation
protocol PicsManagerDelegate {
func didUpdatePics(_ pics: PicsModel)
}
struct PicsManager {
var currentPage: Int = 1
let picsURL = "https://api.unsplash.com/search/photos/"
var delegate: PicsManagerDelegate?
let API_Key = "Your API Key here"
enum OrderBy {
case latest
case oldest
case popular
}
var searchURL: String {
return ("\(picsURL)?client_id=\(API_Key)&page=\(String(currentPage))")
}
func getPics(_ term: String) {
let fullURL = "\(searchURL)&query=\(term)"
self.performRequest(with: fullURL)
}
func performRequest(with urlString: String) {
if let url = URL(string: urlString) {
let session = URLSession(configuration: .default)
let task = session.dataTask(with: url, completionHandler: { (data, response, error) in
if error != nil {
print("Error: \(error!)")
return
}
if let data = data {
print("calling parseJSON")
self.parseJSON(data)
// let dataString = String(data: data, encoding: .utf8)
// print(dataString!)
} else {
print("No data!!")
}
})
task.resume()
}
}
func parseJSON(_ picsData: Data) {
let pics = PicsModel()
do {
let decodedData = try JSONDecoder().decode(PicsData.self, from: picsData)
print("Decoded data:\n\(decodedData.results[0].urls.small)")
var downloadedPics: [Result] = []
downloadedPics += decodedData.results
// print("~~~ ~~~ ~~~")
// print(downloadedPics)
for item in decodedData.results {
let pic = PicDetails(userName: item.user.name, title: item.alt_description, smallPicUrl: item.urls.small, largePicUrl: item.urls.full)
pics.pics.append(pic)
}
self.delegate?.didUpdatePics(pics)
} catch let error {
print("Error decoding data: \(error)")
}
}
}
PicsData.swift
//
// PicsData.swift
// UIKit_ProgrammaticUI_SearchBar
//
// Created by Matteo on 01/09/2021.
//
import Foundation
struct PicsData: Decodable {
let total: Int
let total_pages: Int
let results: [Result]
}
struct Result: Decodable {
let id: String
let alt_description: String
let likes: Int
let user: User
let urls: URLS
}
struct User: Decodable {
let id: String
let name: String
}
struct URLS: Decodable {
let thumb: String
let small: String
let regular: String
let full: String
let raw: String
}
PicsModel.swift
//
// PicsModel.swift
// UIKit_ProgrammaticUI_SearchBar
//
// Created by Matteo on 05/09/2021.
//
import UIKit
class PicsModel {
var pics: [PicDetails] = []
}
struct PicDetails {
var userName: String
var title: String
var smallPicUrl: String
var largePicUrl: String
// var smallPicData: UIImageView {
// return self.getPicData(smallPic)
// }
// var getShortUserName: String {
// var nameString = userName
// nameString = nameString.trimmingCharacters(in: .whitespacesAndNewlines)
// let start = nameString.index(nameString.startIndex, offsetBy: 0)
// let end = nameString.index(nameString.startIndex, offsetBy: 9)
// let range = start...end
// nameString = String(nameString[range])
// return nameString
// }
var getUserName: String {
var nameString = userName
nameString = nameString.trimmingCharacters(in: .whitespacesAndNewlines)
return nameString
}
// func getPicData(_ urlString: String) -> UIImageView {
// let img = UIImageView()
//
// DispatchQueue.global(qos: .userInitiated).async {
// if let url = URL(string: urlString) {
// let session = URLSession(configuration: .default)
// let task = session.dataTask(with: url, completionHandler: { data, response, error in
// if error != nil {
// img.backgroundColor = .systemRed
// }
//
// if let data = data {
// DispatchQueue.main.async {
// img.image = UIImage(data: data)
// }
// }
// })
// task.resume()
// }
// }
// return img
// }
}
欢迎来到 Whosebug,Mabus!
你错过了一个导致错误的小东西,如果你在 CollectionViewCell
class 中查看 setupLayout
方法,你会注意到你忘记添加 backgroundImageView
到单元格的内容视图。
我在 setupLayout
方法中添加了一些代码行只是为了演示出了什么问题,所以请忽略单元格的美感:3
private func setupLayout() {
self.contentView.addSubview(roundedBackgroundView)
roundedBackgroundView.addSubview(picLabel)
roundedBackgroundView.addSubview(backgroundImageView)
NSLayoutConstraint.activate([
roundedBackgroundView.topAnchor.constraint(equalTo: self.contentView.topAnchor, constant: 5),
roundedBackgroundView.bottomAnchor.constraint(equalTo: self.contentView.bottomAnchor, constant: -5),
roundedBackgroundView.leadingAnchor.constraint(equalTo: self.contentView.leadingAnchor, constant: 5),
roundedBackgroundView.trailingAnchor.constraint(equalTo: self.contentView.trailingAnchor, constant: -5),
backgroundImageView.centerXAnchor.constraint(equalTo: roundedBackgroundView.centerXAnchor),
backgroundImageView.centerYAnchor.constraint(equalTo: roundedBackgroundView.centerYAnchor),
picLabel.centerXAnchor.constraint(equalTo: self.contentView.centerXAnchor),
picLabel.centerYAnchor.constraint(equalTo: self.contentView.bottomAnchor, constant: -15)
])
}
这就是您的应用目前的样子:
我正在尝试显示一些使用 UICollectionView 从 Unsplash 获取的图片。这个想法是显示一个带有图像和作者姓名的单元格。 目前我只能显示单元格的边框和作者姓名,无论我如何处理无法显示 UIImage 的问题。 我在各处都添加了打印输出(是的,我提到过我是初学者...)并且我可以打印 url 字符串和对图像对象的引用。 我想知道我在 UIImageView 中显示 UIImage 的方式是否有问题,如果出于某种原因在绘制 View 时 UIImage 尚未准备好(我知道我必须获取它,为什么我可以打印它?)。
这是我的代码:
ViewController.swift
import UIKit
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .systemBackground
view.addSubview(titleView)
view.addSubview(searchBarView)
view.addSubview(collectionView)
searchBarView.delegate = self
collectionView.delegate = self
collectionView.dataSource = self
picsManager.delegate = self
setupLayout()
}
var picsManager = PicsManager()
var pics = PicsModel()
func setupLayout() {
NSLayoutConstraint.activate([
titleView.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor),
titleView.leadingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.leadingAnchor),
titleView.trailingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.trailingAnchor),
titleView.widthAnchor.constraint(equalTo: view.widthAnchor),
searchBarView.topAnchor.constraint(equalTo: titleView.bottomAnchor, constant: 10),
searchBarView.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 20),
searchBarView.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -20),
// collectionView.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor),
collectionView.topAnchor.constraint(equalTo: searchBarView.bottomAnchor),
collectionView.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor),
collectionView.leadingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.leadingAnchor),
collectionView.trailingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.trailingAnchor)
])
}
let titleView: UILabel = {
let tv = UILabel()
tv.translatesAutoresizingMaskIntoConstraints = false
// tv.font = UIFont.preferredFont(forTextStyle: .largeTitle)
tv.font = UIFont(name: "Georgia-Italic", size: 44)
tv.textColor = .systemBlue
tv.textAlignment = .center
tv.text = "Coins Live"
tv.sizeToFit()
return tv
}()
let searchBarView: UISearchBar = {
let sb = UISearchBar()
sb.translatesAutoresizingMaskIntoConstraints = false
sb.searchBarStyle = .default
sb.placeholder = "Search..."
sb.sizeToFit()
sb.isTranslucent = false
sb.showsCancelButton = false
return sb
}()
lazy var collectionView: UICollectionView = {
let layout = UICollectionViewFlowLayout()
layout.sectionInset = UIEdgeInsets(top: 0,
left: 10,
bottom: 0,
right: 10)
layout.minimumInteritemSpacing = 10
layout.minimumLineSpacing = 10
layout.scrollDirection = .vertical
let cv = UICollectionView(frame: .zero, collectionViewLayout: layout)
cv.backgroundColor = .systemYellow
cv.translatesAutoresizingMaskIntoConstraints = false
cv.register(CollectionViewCell.self, forCellWithReuseIdentifier: "CollectionViewCell")
return cv
}()
}
//MARK: - Extension UICollectionView
extension ViewController: UICollectionViewDelegateFlowLayout, UICollectionViewDelegate, UICollectionViewDataSource {
// Dimensions of the cell
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
// return CGSize(width: collectionView.frame.width / 3.5, height: collectionView.frame.width / 3.5)
return CGSize(width: collectionView.frame.width / 1.1, height: collectionView.frame.width / 1.1)
}
// How many cells
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return pics.pics.count
}
// Details of each cell
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "CollectionViewCell", for: indexPath) as! CollectionViewCell
cell.picLabel.text = pics.pics[indexPath.item].getUserName
// METHOD ONE
// let url = URL(string: pics.pics[indexPath.item].smallPicUrl)!
// let data = try? Data(contentsOf: url)
// let img = UIImage(data: data!)
// cell.backgroundImageView.image = img
// METHOD TWO
// let task = URLSession.shared.dataTask(with: url, completionHandler: { data, response, error in
// if error != nil {
// print("Error")
// return
// }
//
// if let data = data {
// DispatchQueue.main.async {
// cell.backgroundImageView = UIImageView(image: UIImage(data: data))
// print("cellForItemAt \(indexPath.item) : \(self.pics.pics[indexPath.item].smallPicUrl)")
// }
// }
// })
//
// task.resume()
// METHOD THREE
let urlString = pics.pics[indexPath.item].smallPicUrl
cell.configure(with: urlString)
return cell
}
}
extension ViewController: UISearchBarDelegate {
// Contents of the searchBar are sent, but only after a delay. This is to prevent sending
// a request after every character. Better to wait until the user has finished typing.
func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) {
NSObject.cancelPreviousPerformRequests(withTarget: self, selector: #selector(self.reload(_:)), object: searchBar)
perform(#selector(self.reload(_:)), with: searchBar, afterDelay: 0.5)
}
@objc func reload(_ searchBar: UISearchBar) {
guard let query = searchBar.text, query.trimmingCharacters(in: .whitespaces) != "" else {
print("nothing to search")
return
}
if let term = searchBar.searchTextField.text {
picsManager.getPics(term)
} else {
print("Invalid query.")
}
}
}
extension ViewController: PicsManagerDelegate {
func didUpdatePics(_ pics: PicsModel) {
DispatchQueue.main.async {
self.pics = pics
self.collectionView.reloadData()
// print("~~~ ~~~ ~~~ ~~~ ~~~ ~~~")
// print(pics.pics[0].smallPicUrl)
}
}
}
CollectionViewCell.swift
//
// CollectionViewCell.swift
// UIKit_ProgrammaticUI_SearchBar
//
// Created by Matteo on 31/08/2021.
//
import UIKit
class CollectionViewCell: UICollectionViewCell {
//MARK: - Init
override init(frame: CGRect) {
super.init(frame: frame)
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override func layoutSubviews() {
setupLayout()
}
//MARK: - Properties
lazy var roundedBackgroundView: UIView = {
let view = UIView()
view.translatesAutoresizingMaskIntoConstraints = false
view.layer.cornerRadius = 10
view.layer.borderWidth = 2
view.layer.borderColor = UIColor.systemTeal.cgColor
return view
}()
lazy var picLabel: UILabel = {
let label = UILabel()
label.translatesAutoresizingMaskIntoConstraints = false
label.font = UIFont(name: "HelveticaNeue", size: 13)
label.textColor = .systemIndigo
return label
}()
lazy var backgroundImageView: UIImageView = {
let iv = UIImageView()
iv.translatesAutoresizingMaskIntoConstraints = false
iv.layer.cornerRadius = 10
iv.layer.borderWidth = 2
iv.layer.borderColor = UIColor.systemTeal.cgColor
return iv
}()
}
//MARK: - Layout
extension CollectionViewCell {
private func setupLayout() {
// When configuring a view, you add any custom subview to self.contentView
// Option + leftClick for more info!
self.contentView.addSubview(roundedBackgroundView)
roundedBackgroundView.addSubview(picLabel)
NSLayoutConstraint.activate([
roundedBackgroundView.topAnchor.constraint(equalTo: self.contentView.topAnchor, constant: 5),
roundedBackgroundView.bottomAnchor.constraint(equalTo: self.contentView.bottomAnchor, constant: -5),
roundedBackgroundView.leadingAnchor.constraint(equalTo: self.contentView.leadingAnchor, constant: 5),
roundedBackgroundView.trailingAnchor.constraint(equalTo: self.contentView.trailingAnchor, constant: -5),
picLabel.centerXAnchor.constraint(equalTo: self.contentView.centerXAnchor),
picLabel.centerYAnchor.constraint(equalTo: self.contentView.bottomAnchor, constant: -15)
])
}
func configure(with urlString: String) {
guard let url = URL(string: urlString) else { return }
URLSession.shared.dataTask(with: url, completionHandler: { [weak self] data, _, error in
guard let data = data, error == nil else { return }
DispatchQueue.main.async {
let image = UIImage(data: data)
self!.backgroundImageView.image = image
print("~~~~~ ~~~~~ ~~~~~")
print(self?.backgroundImageView.image ?? "nothing to print here...")
}
}).resume()
}
}
PicsManager.swift
//
// PicsManager.swift
// UIKit_ProgrammaticUI_SearchBar
//
// Created by Matteo on 01/09/2021.
//
import Foundation
protocol PicsManagerDelegate {
func didUpdatePics(_ pics: PicsModel)
}
struct PicsManager {
var currentPage: Int = 1
let picsURL = "https://api.unsplash.com/search/photos/"
var delegate: PicsManagerDelegate?
let API_Key = "Your API Key here"
enum OrderBy {
case latest
case oldest
case popular
}
var searchURL: String {
return ("\(picsURL)?client_id=\(API_Key)&page=\(String(currentPage))")
}
func getPics(_ term: String) {
let fullURL = "\(searchURL)&query=\(term)"
self.performRequest(with: fullURL)
}
func performRequest(with urlString: String) {
if let url = URL(string: urlString) {
let session = URLSession(configuration: .default)
let task = session.dataTask(with: url, completionHandler: { (data, response, error) in
if error != nil {
print("Error: \(error!)")
return
}
if let data = data {
print("calling parseJSON")
self.parseJSON(data)
// let dataString = String(data: data, encoding: .utf8)
// print(dataString!)
} else {
print("No data!!")
}
})
task.resume()
}
}
func parseJSON(_ picsData: Data) {
let pics = PicsModel()
do {
let decodedData = try JSONDecoder().decode(PicsData.self, from: picsData)
print("Decoded data:\n\(decodedData.results[0].urls.small)")
var downloadedPics: [Result] = []
downloadedPics += decodedData.results
// print("~~~ ~~~ ~~~")
// print(downloadedPics)
for item in decodedData.results {
let pic = PicDetails(userName: item.user.name, title: item.alt_description, smallPicUrl: item.urls.small, largePicUrl: item.urls.full)
pics.pics.append(pic)
}
self.delegate?.didUpdatePics(pics)
} catch let error {
print("Error decoding data: \(error)")
}
}
}
PicsData.swift
//
// PicsData.swift
// UIKit_ProgrammaticUI_SearchBar
//
// Created by Matteo on 01/09/2021.
//
import Foundation
struct PicsData: Decodable {
let total: Int
let total_pages: Int
let results: [Result]
}
struct Result: Decodable {
let id: String
let alt_description: String
let likes: Int
let user: User
let urls: URLS
}
struct User: Decodable {
let id: String
let name: String
}
struct URLS: Decodable {
let thumb: String
let small: String
let regular: String
let full: String
let raw: String
}
PicsModel.swift
//
// PicsModel.swift
// UIKit_ProgrammaticUI_SearchBar
//
// Created by Matteo on 05/09/2021.
//
import UIKit
class PicsModel {
var pics: [PicDetails] = []
}
struct PicDetails {
var userName: String
var title: String
var smallPicUrl: String
var largePicUrl: String
// var smallPicData: UIImageView {
// return self.getPicData(smallPic)
// }
// var getShortUserName: String {
// var nameString = userName
// nameString = nameString.trimmingCharacters(in: .whitespacesAndNewlines)
// let start = nameString.index(nameString.startIndex, offsetBy: 0)
// let end = nameString.index(nameString.startIndex, offsetBy: 9)
// let range = start...end
// nameString = String(nameString[range])
// return nameString
// }
var getUserName: String {
var nameString = userName
nameString = nameString.trimmingCharacters(in: .whitespacesAndNewlines)
return nameString
}
// func getPicData(_ urlString: String) -> UIImageView {
// let img = UIImageView()
//
// DispatchQueue.global(qos: .userInitiated).async {
// if let url = URL(string: urlString) {
// let session = URLSession(configuration: .default)
// let task = session.dataTask(with: url, completionHandler: { data, response, error in
// if error != nil {
// img.backgroundColor = .systemRed
// }
//
// if let data = data {
// DispatchQueue.main.async {
// img.image = UIImage(data: data)
// }
// }
// })
// task.resume()
// }
// }
// return img
// }
}
欢迎来到 Whosebug,Mabus!
你错过了一个导致错误的小东西,如果你在 CollectionViewCell
class 中查看 setupLayout
方法,你会注意到你忘记添加 backgroundImageView
到单元格的内容视图。
我在 setupLayout
方法中添加了一些代码行只是为了演示出了什么问题,所以请忽略单元格的美感:3
private func setupLayout() {
self.contentView.addSubview(roundedBackgroundView)
roundedBackgroundView.addSubview(picLabel)
roundedBackgroundView.addSubview(backgroundImageView)
NSLayoutConstraint.activate([
roundedBackgroundView.topAnchor.constraint(equalTo: self.contentView.topAnchor, constant: 5),
roundedBackgroundView.bottomAnchor.constraint(equalTo: self.contentView.bottomAnchor, constant: -5),
roundedBackgroundView.leadingAnchor.constraint(equalTo: self.contentView.leadingAnchor, constant: 5),
roundedBackgroundView.trailingAnchor.constraint(equalTo: self.contentView.trailingAnchor, constant: -5),
backgroundImageView.centerXAnchor.constraint(equalTo: roundedBackgroundView.centerXAnchor),
backgroundImageView.centerYAnchor.constraint(equalTo: roundedBackgroundView.centerYAnchor),
picLabel.centerXAnchor.constraint(equalTo: self.contentView.centerXAnchor),
picLabel.centerYAnchor.constraint(equalTo: self.contentView.bottomAnchor, constant: -15)
])
}
这就是您的应用目前的样子: