我可以在 ViewDidLoad 中加载 UICollectionView 的数据吗?
Can I load a UICollectionView's data in ViewDidLoad?
我的应用程序的启动屏幕是一个集合视图。如果用户选择,he/she 可以 "lock" 应用在应用启动时使用人脸 ID/Touch ID。我通过在我的集合视图控制器之上呈现一个包含 UIVisualEffectView
的视图控制器来实现这一点。我在 viewDidLoad
中截图了我的集合视图控制器,然后将截图放在 UIVisualEffectView
下方的 UIImageView
中。
问题是,截取屏幕截图并出现 UIVisualEffectView
控制器时,集合视图未加载。屏幕截图包含导航栏,但视图的内容只是黑色。我在集合视图的 viewDidLoad
函数中调用了显示视觉效果视图控制器的函数。
在 viewDidLoad
截屏之前,有没有办法加载集合视图的数据?数据存储在核心数据中。我已经尝试将 Core Data 函数从 viewWillAppear
移动到 viewDidLoad
,但这也没有用。
编辑:我能够解决我的问题,但不能通过在 ViewDidLoad 中加载我的 UICollectionView
数据来解决,因为这似乎是不可能的。我直接在 UICollectionView
之上添加了一个 UIVisualEffectView
。我还将它添加为 UIApplication.shared.keyWindow
的子视图,以便它显示在导航栏上方。编辑后的代码在下面。
这是我的代码:
对于集合视图控制器:
import UIKit
import CoreData
import LocalAuthentication
var ssImage: UIImage?
class AlbumViewController: UIViewController {
// MARK: - Properties
@IBOutlet weak var albumCollectionView: UICollectionView!
var albums: [NSManagedObject] = []
// MARK: - Actions
func getScreenShot()-> UIImage? {
var screenshotImage :UIImage?
let layer = UIApplication.shared.keyWindow!.layer
let scale = UIScreen.main.scale
UIGraphicsBeginImageContextWithOptions(layer.frame.size, false, scale);
guard let context = UIGraphicsGetCurrentContext() else {return nil}
layer.render(in:context)
screenshotImage = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
ssImage = screenshotImage
print("Got screenshot.")
return screenshotImage
}
// ViewDidLoad and ViewWillAppear
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
//Core Date functions
guard let appDelegate =
UIApplication.shared.delegate as? AppDelegate else {
return
}
let managedContext =
appDelegate.persistentContainer.viewContext
let fetchRequest =
NSFetchRequest<NSManagedObject>(entityName: "Album")
let sortDescriptor = NSSortDescriptor(key: "albumName", ascending: true, selector: #selector(NSString.localizedCaseInsensitiveCompare(_:)))
fetchRequest.sortDescriptors = [sortDescriptor]
do {
albums = try managedContext.fetch(fetchRequest)
} catch let error as NSError {
print("Could not fetch. \(error), \(error.userInfo)")
}
//Setup
self.albumCollectionView.reloadData()
}
override func viewDidLoad() {
super.viewDidLoad()
if AppSettings.requiresLogin == true {
getScreenShot()
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let rootController = storyboard.instantiateViewController(withIdentifier: "authenticateVC") as! LockedLaunchVC
self.present(rootController, animated: false, completion: nil)
}
}
//Core Data functions
func save(name: String) {
guard let appDelegate =
UIApplication.shared.delegate as? AppDelegate else {
return
}
let managedContext =
appDelegate.persistentContainer.viewContext
let entity =
NSEntityDescription.entity(forEntityName: "Album",
in: managedContext)!
let albumName = NSManagedObject(entity: entity,
insertInto: managedContext)
albumName.setValue(name, forKeyPath: "albumName")
do {
try managedContext.save()
albums.append(albumName)
} catch let error as NSError {
print("Could not save. \(error), \(error.userInfo)")
}
}
}
//Collection View functions
extension AlbumViewController: UICollectionViewDataSource, UICollectionViewDelegate {
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return albums.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let reuseIdentifier = "AlbumCell"
// get a reference to our storyboard cell
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: reuseIdentifier, for: indexPath as IndexPath) as! AlbumsViewCell
//Core Data methods
let albumName = albums[indexPath.row]
cell.albumNameLabel?.text = albumName.value(forKeyPath: "albumName") as? String
//Return the finished cell
return cell
}
}
对于 UIVisualEffectView 控制器:
import UIKit
import LocalAuthentication
class LockedLaunchVC: UIViewController {
let bioIDAuth = BiometricIDAuth()
@IBOutlet weak var screenshotImageView: UIImageView!
@IBAction func unlockButtonTapped(_ sender: UIButton) {
authAndDismiss()
}
func authAndDismiss(){
bioIDAuth.authenticateUser() {
self.dismiss(animated: true, completion: nil)
print("Locked VC dismissed.")
}
}
override func viewDidLoad() {
super.viewDidLoad()
self.modalTransitionStyle = .crossDissolve
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
screenshotImageView.image = ssImage
}
}
编辑:我的集合视图控制器的修订代码:
import UIKit
import CoreData
class AlbumViewController: UIViewController {
// MARK: - Properties
@IBOutlet weak var albumCollectionView: UICollectionView!
@IBOutlet weak var lockedBlurView: UIVisualEffectView!
@IBOutlet weak var lockedLabelView: UIView!
@IBOutlet weak var lockedLabel: UILabel!
var albums: [NSManagedObject] = []
let bioIDAuth = BiometricIDAuth()
// MARK: - Actions
@IBAction func unwindToAlbumsScreen(sender: UIStoryboardSegue) {
}
@IBAction func unlockButtonTapped(_ sender: UIButton) {
bioIDAuth.authenticateUser() {
UIView.animate(withDuration: 0.25, animations: {self.lockedBlurView.alpha = 0})
}
}
// ViewDidLoad and ViewWillAppear
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
//Core Date functions
guard let appDelegate =
UIApplication.shared.delegate as? AppDelegate else {
return
}
let managedContext =
appDelegate.persistentContainer.viewContext
let fetchRequest =
NSFetchRequest<NSManagedObject>(entityName: "Album")
let sortDescriptor = NSSortDescriptor(key: "albumName", ascending: true, selector: #selector(NSString.localizedCaseInsensitiveCompare(_:)))
fetchRequest.sortDescriptors = [sortDescriptor]
do {
albums = try managedContext.fetch(fetchRequest)
} catch let error as NSError {
print("Could not fetch. \(error), \(error.userInfo)")
}
//Setup to do when the view will appear
self.albumCollectionView.reloadData()
}
override func viewDidLoad() {
super.viewDidLoad()
lockedLabelView.layer.cornerRadius = 12
switch bioIDAuth.biometricType() {
case .faceID:
lockedLabel.text = "Albums are locked. Tap anywhere to use Face ID to unlock."
case .touchID:
lockedLabel.text = "Albums are locked. Tap anywhere to use Touch ID to unlock."
default:
lockedLabel.text = "Albums are locked. Tap anywhere to use your passcode to unlock."
}
if AppSettings.requiresLogin == false {
lockedBlurView.alpha = 0
}
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
if AppSettings.requiresLogin == true {
let curWin = UIApplication.shared.keyWindow
curWin?.addSubview(lockedBlurView)
}
}
//Core Data functions
func save(name: String) {
guard let appDelegate =
UIApplication.shared.delegate as? AppDelegate else {
return
}
let managedContext =
appDelegate.persistentContainer.viewContext
let entity =
NSEntityDescription.entity(forEntityName: "Album",
in: managedContext)!
let albumName = NSManagedObject(entity: entity,
insertInto: managedContext)
albumName.setValue(name, forKeyPath: "albumName")
do {
try managedContext.save()
albums.append(albumName)
} catch let error as NSError {
print("Could not save. \(error), \(error.userInfo)")
}
}
}
//Collection View functions
extension AlbumViewController: UICollectionViewDataSource, UICollectionViewDelegate {
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return albums.count
}
// make a cell for each cell index path
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let reuseIdentifier = "AlbumCell"
// get a reference to our storyboard cell
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: reuseIdentifier, for: indexPath as IndexPath) as! AlbumsViewCell
//Core Data methods
let albumName = albums[indexPath.row]
cell.albumNameLabel?.text = albumName.value(forKeyPath: "albumName") as? String
//Return the finished cell
return cell
}
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
let albumNameFromCell = albums[indexPath.row]
albumNameTapped = albumNameFromCell.value(forKeyPath: "albumName") as! String
self.performSegue(withIdentifier: "albumCellTappedSegue", sender: self)
}
}
您似乎无法在 viewDidLoad
中加载任何视图的内容。根据 Apple View Controller Programming Guide,“viewDidLoad
在创建视图控制器的内容视图(其视图层次结构的顶部)并从故事板加载时调用。”基本上,当视图控制器及其子视图加载但不可见时调用它。 ViewDidAppear
是视图控制器及其子视图可见的地方。根据 Apple View Controller Programming Guide,“viewDidAppear
在视图控制器的内容视图被添加到应用程序的视图层次结构之后被调用。”换句话说,视图控制器及其子视图已经可见。
我能够解决我的问题,尽管它的答案没有回答这个问题。我将该问题的答案添加为对我的问题的编辑。
我的应用程序的启动屏幕是一个集合视图。如果用户选择,he/she 可以 "lock" 应用在应用启动时使用人脸 ID/Touch ID。我通过在我的集合视图控制器之上呈现一个包含 UIVisualEffectView
的视图控制器来实现这一点。我在 viewDidLoad
中截图了我的集合视图控制器,然后将截图放在 UIVisualEffectView
下方的 UIImageView
中。
问题是,截取屏幕截图并出现 UIVisualEffectView
控制器时,集合视图未加载。屏幕截图包含导航栏,但视图的内容只是黑色。我在集合视图的 viewDidLoad
函数中调用了显示视觉效果视图控制器的函数。
在 viewDidLoad
截屏之前,有没有办法加载集合视图的数据?数据存储在核心数据中。我已经尝试将 Core Data 函数从 viewWillAppear
移动到 viewDidLoad
,但这也没有用。
编辑:我能够解决我的问题,但不能通过在 ViewDidLoad 中加载我的 UICollectionView
数据来解决,因为这似乎是不可能的。我直接在 UICollectionView
之上添加了一个 UIVisualEffectView
。我还将它添加为 UIApplication.shared.keyWindow
的子视图,以便它显示在导航栏上方。编辑后的代码在下面。
这是我的代码:
对于集合视图控制器:
import UIKit
import CoreData
import LocalAuthentication
var ssImage: UIImage?
class AlbumViewController: UIViewController {
// MARK: - Properties
@IBOutlet weak var albumCollectionView: UICollectionView!
var albums: [NSManagedObject] = []
// MARK: - Actions
func getScreenShot()-> UIImage? {
var screenshotImage :UIImage?
let layer = UIApplication.shared.keyWindow!.layer
let scale = UIScreen.main.scale
UIGraphicsBeginImageContextWithOptions(layer.frame.size, false, scale);
guard let context = UIGraphicsGetCurrentContext() else {return nil}
layer.render(in:context)
screenshotImage = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
ssImage = screenshotImage
print("Got screenshot.")
return screenshotImage
}
// ViewDidLoad and ViewWillAppear
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
//Core Date functions
guard let appDelegate =
UIApplication.shared.delegate as? AppDelegate else {
return
}
let managedContext =
appDelegate.persistentContainer.viewContext
let fetchRequest =
NSFetchRequest<NSManagedObject>(entityName: "Album")
let sortDescriptor = NSSortDescriptor(key: "albumName", ascending: true, selector: #selector(NSString.localizedCaseInsensitiveCompare(_:)))
fetchRequest.sortDescriptors = [sortDescriptor]
do {
albums = try managedContext.fetch(fetchRequest)
} catch let error as NSError {
print("Could not fetch. \(error), \(error.userInfo)")
}
//Setup
self.albumCollectionView.reloadData()
}
override func viewDidLoad() {
super.viewDidLoad()
if AppSettings.requiresLogin == true {
getScreenShot()
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let rootController = storyboard.instantiateViewController(withIdentifier: "authenticateVC") as! LockedLaunchVC
self.present(rootController, animated: false, completion: nil)
}
}
//Core Data functions
func save(name: String) {
guard let appDelegate =
UIApplication.shared.delegate as? AppDelegate else {
return
}
let managedContext =
appDelegate.persistentContainer.viewContext
let entity =
NSEntityDescription.entity(forEntityName: "Album",
in: managedContext)!
let albumName = NSManagedObject(entity: entity,
insertInto: managedContext)
albumName.setValue(name, forKeyPath: "albumName")
do {
try managedContext.save()
albums.append(albumName)
} catch let error as NSError {
print("Could not save. \(error), \(error.userInfo)")
}
}
}
//Collection View functions
extension AlbumViewController: UICollectionViewDataSource, UICollectionViewDelegate {
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return albums.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let reuseIdentifier = "AlbumCell"
// get a reference to our storyboard cell
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: reuseIdentifier, for: indexPath as IndexPath) as! AlbumsViewCell
//Core Data methods
let albumName = albums[indexPath.row]
cell.albumNameLabel?.text = albumName.value(forKeyPath: "albumName") as? String
//Return the finished cell
return cell
}
}
对于 UIVisualEffectView 控制器:
import UIKit
import LocalAuthentication
class LockedLaunchVC: UIViewController {
let bioIDAuth = BiometricIDAuth()
@IBOutlet weak var screenshotImageView: UIImageView!
@IBAction func unlockButtonTapped(_ sender: UIButton) {
authAndDismiss()
}
func authAndDismiss(){
bioIDAuth.authenticateUser() {
self.dismiss(animated: true, completion: nil)
print("Locked VC dismissed.")
}
}
override func viewDidLoad() {
super.viewDidLoad()
self.modalTransitionStyle = .crossDissolve
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
screenshotImageView.image = ssImage
}
}
编辑:我的集合视图控制器的修订代码:
import UIKit
import CoreData
class AlbumViewController: UIViewController {
// MARK: - Properties
@IBOutlet weak var albumCollectionView: UICollectionView!
@IBOutlet weak var lockedBlurView: UIVisualEffectView!
@IBOutlet weak var lockedLabelView: UIView!
@IBOutlet weak var lockedLabel: UILabel!
var albums: [NSManagedObject] = []
let bioIDAuth = BiometricIDAuth()
// MARK: - Actions
@IBAction func unwindToAlbumsScreen(sender: UIStoryboardSegue) {
}
@IBAction func unlockButtonTapped(_ sender: UIButton) {
bioIDAuth.authenticateUser() {
UIView.animate(withDuration: 0.25, animations: {self.lockedBlurView.alpha = 0})
}
}
// ViewDidLoad and ViewWillAppear
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
//Core Date functions
guard let appDelegate =
UIApplication.shared.delegate as? AppDelegate else {
return
}
let managedContext =
appDelegate.persistentContainer.viewContext
let fetchRequest =
NSFetchRequest<NSManagedObject>(entityName: "Album")
let sortDescriptor = NSSortDescriptor(key: "albumName", ascending: true, selector: #selector(NSString.localizedCaseInsensitiveCompare(_:)))
fetchRequest.sortDescriptors = [sortDescriptor]
do {
albums = try managedContext.fetch(fetchRequest)
} catch let error as NSError {
print("Could not fetch. \(error), \(error.userInfo)")
}
//Setup to do when the view will appear
self.albumCollectionView.reloadData()
}
override func viewDidLoad() {
super.viewDidLoad()
lockedLabelView.layer.cornerRadius = 12
switch bioIDAuth.biometricType() {
case .faceID:
lockedLabel.text = "Albums are locked. Tap anywhere to use Face ID to unlock."
case .touchID:
lockedLabel.text = "Albums are locked. Tap anywhere to use Touch ID to unlock."
default:
lockedLabel.text = "Albums are locked. Tap anywhere to use your passcode to unlock."
}
if AppSettings.requiresLogin == false {
lockedBlurView.alpha = 0
}
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
if AppSettings.requiresLogin == true {
let curWin = UIApplication.shared.keyWindow
curWin?.addSubview(lockedBlurView)
}
}
//Core Data functions
func save(name: String) {
guard let appDelegate =
UIApplication.shared.delegate as? AppDelegate else {
return
}
let managedContext =
appDelegate.persistentContainer.viewContext
let entity =
NSEntityDescription.entity(forEntityName: "Album",
in: managedContext)!
let albumName = NSManagedObject(entity: entity,
insertInto: managedContext)
albumName.setValue(name, forKeyPath: "albumName")
do {
try managedContext.save()
albums.append(albumName)
} catch let error as NSError {
print("Could not save. \(error), \(error.userInfo)")
}
}
}
//Collection View functions
extension AlbumViewController: UICollectionViewDataSource, UICollectionViewDelegate {
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return albums.count
}
// make a cell for each cell index path
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let reuseIdentifier = "AlbumCell"
// get a reference to our storyboard cell
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: reuseIdentifier, for: indexPath as IndexPath) as! AlbumsViewCell
//Core Data methods
let albumName = albums[indexPath.row]
cell.albumNameLabel?.text = albumName.value(forKeyPath: "albumName") as? String
//Return the finished cell
return cell
}
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
let albumNameFromCell = albums[indexPath.row]
albumNameTapped = albumNameFromCell.value(forKeyPath: "albumName") as! String
self.performSegue(withIdentifier: "albumCellTappedSegue", sender: self)
}
}
您似乎无法在 viewDidLoad
中加载任何视图的内容。根据 Apple View Controller Programming Guide,“viewDidLoad
在创建视图控制器的内容视图(其视图层次结构的顶部)并从故事板加载时调用。”基本上,当视图控制器及其子视图加载但不可见时调用它。 ViewDidAppear
是视图控制器及其子视图可见的地方。根据 Apple View Controller Programming Guide,“viewDidAppear
在视图控制器的内容视图被添加到应用程序的视图层次结构之后被调用。”换句话说,视图控制器及其子视图已经可见。
我能够解决我的问题,尽管它的答案没有回答这个问题。我将该问题的答案添加为对我的问题的编辑。