【问题标题】:Can I load a UICollectionView's data in ViewDidLoad?我可以在 ViewDidLoad 中加载 UICollectionView 的数据吗?
【发布时间】:2018-10-11 20:30:31
【问题描述】:

我的应用程序的启动屏幕是一个集合视图。如果用户选择,他/她可以在应用启动时使用 Face ID/Touch ID “锁定”应用。我通过在我的集合视图控制器顶部展示一个包含UIVisualEffectView 的视图控制器来做到这一点。我在viewDidLoad 中截取我的收藏视图控制器,然后将截屏放在UIImageView 下方的UIVisualEffectView 中。

问题是,截屏时没有加载集合视图并出现UIVisualEffectView 控制器。屏幕截图包含导航栏,但视图的内容只是黑色的。我调用该函数在集合视图的viewDidLoad 函数中显示视觉效果视图控制器。

在我在viewDidLoad 中截屏之前,有没有办法加载集合视图的数据?数据存储在核心数据中。我已经尝试将核心数据函数从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)
}
}

【问题讨论】:

  • 在调用viewDidAppear 之前,您真的无法截取屏幕截图。
  • @rmaddy 哦。那么有没有办法做我想做的事情?或者我是否需要重新设计我的登录屏幕,使其没有屏幕截图?
  • 由于您不希望用户在登录屏幕可见时看到任何数据,因此没有理由获取数据的屏幕截图。
  • @rmaddy 我用视觉效果视图模糊了屏幕截图,并使用了交叉溶解模式过渡样式,这样视觉效果视图看起来就像直接放在集合视图的顶部。所以有必要重新设计我的登录屏幕吗?
  • 我可能错了,但您的快照是黑色的,因为我相信您确实需要在实际屏幕上查看视图,以便在运行时正确拍摄快照。您是否考虑过在您的集合之上添加一个具有清晰背景的 UIView 并在其上添加效果?

标签: ios swift core-data uicollectionview viewdidload


【解决方案1】:

您似乎无法在viewDidLoad 中加载任何视图的内容。根据 Apple 视图控制器编程指南,“viewDidLoad 在创建视图控制器的内容视图(其视图层次结构的顶部)并从情节提要中加载时被调用。”基本上,它在视图控制器及其子视图被加载但不可见时被调用。 ViewDidAppear 是视图控制器及其子视图可见的地方。根据 Apple 视图控制器编程指南,“viewDidAppear 在视图控制器的内容视图被添加到应用程序的视图层次结构之后被调用。”换句话说,视图控制器及其子视图已经可见。

我能够解决我的问题,尽管它的答案没有回答这个问题。我添加了该问题的答案作为对我的问题的修改。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2018-12-11
    • 1970-01-01
    • 1970-01-01
    • 2011-11-24
    • 1970-01-01
    • 2013-01-12
    • 2011-04-13
    • 1970-01-01
    相关资源
    最近更新 更多