在segue push上,UIImage返回nil

时间:2018-04-23 16:58:34

标签: swift xcode image parsing null

我有一个需要解析和显示的图片网址。 URL存在,但返回nil。

通过调用 cell.recipeImage.downloadImage(来自:(self.tableViewDataSource [indexPath.item] .image))成功解析cellForRowAt函数 使用此行显示图像。但是,在didSelectRowAt

中调用它时不存在

RecipeTableViewController.swift

override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
    let Storyboard = UIStoryboard(name: "Main", bundle: nil)
    let resultsVC = Storyboard.instantiateViewController(withIdentifier: "ResultsViewController") as! ResultsViewController

    // Information to be passed to ResultsViewController

    if (tableViewDataSource[indexPath.item] as? Recipe) != nil  {
        if isSearching {
            resultsVC.getTitle = filteredData[indexPath.row].title
            //resultsVC.imageDisplay.downloadImage(from: (self.filteredData[indexPath.row].image))
        } else {
            resultsVC.getTitle = tableViewDataSource[indexPath.row].title
            // Parse images
            resultsVC.imageDisplay.downloadImage(from: (self.tableViewDataSource[indexPath.row].image))
        }
    }

    // Push to next view
    self.navigationController?.pushViewController(resultsVC, animated: true)
}

extension UIImageView {
func downloadImage(from url: String) {
    let urlRequest = URLRequest(url: URL(string: url)!)
    let task = URLSession.shared.dataTask(with: urlRequest) { (data,response,error) in
        if error != nil {
            print(error!)
            return
        }
        DispatchQueue.main.sync {
            self.image = UIImage(data: data!)
        }
    }
    task.resume()
}
}

ResultsViewController.swift

class ResultsViewController: UIViewController {

var getTitle = String()
var getImage = String()

@IBOutlet weak var recipeDisplay: UILabel!
@IBOutlet weak var imageDisplay: UIImageView!

override func viewDidLoad() {
    super.viewDidLoad()

    recipeDisplay.text! = getTitle

}
...
}

返回错误

  

线程1:致命错误:在解包可选值时意外发现nil

2 个答案:

答案 0 :(得分:1)

根据我的理解,该应用程序正在崩溃:

  

recipeDisplay.text! = getTitle

如果是,显然这不是正确的方法。只需删除强制解包,因为默认情况下此处标签上的文本为nil。强制引用nil值会使应用程序崩溃。

  

recipeDisplay.text = getTitle

更新: - 让我们确保您正确连接标签和插座。将ti连接到VC,而不是文件所有者。

答案 1 :(得分:0)

您正在尚未初始化的视图上调用与视图相关的代码。请记住,IBOutlets是隐式展开的属性,因此如果您在初始化之前尝试访问它们,它们将强制解包并崩溃。所以并不是说UIImage的结果是零,这就是recipeDisplay是零并且正在解开力量。

惯用iOS要做的事情是将某种视图模型(对象或结构)交给视图控制器,然后让它在完成加载后对该项进行处理。

所以,在你的didSelect方法中,你可以创建你的视图模型(你需要定义)并将其交给它:

let title = filteredData[indexPath.row].title
let imageURL = self.tableViewDataSource[indexPath.row].image
let viewModel = ViewModel(title: title, imageURL: imageURL)
resultsVC.viewModel = viewModel

然后在你的resultsVC中,你会做这样的事情:

override func viewDidLoad() {
    super.viewDidLoad()
    if let vm = viewModel {
        recipeDisplay.text = vm.title
        downloadImage(from: vm.imageURL)
    }
}

所以在你的情况下,你需要做的就是把这些字符串交给你的VC(你可以将它们包装在一个视图模型中或者单独交出)然后在那个VC的viewDidLoad()那里你打电话给downloadImage(from:)。这样,在加载子视图之前就没有调用子视图的危险。

最后一点说明:使用dataerror变量及其对self的引用,您的下载方法应该更安全一些。请记住,每当您不必使用它时,请避免使用!(请使用可选链接),除非您有充分理由不这样做,否则请始终在闭包中使用[weak self]

我建议这样做:

func downloadImage(from url: String) {
    let urlRequest = URLRequest(url: URL(string: url)!)
    let task = URLSession.shared.dataTask(with: urlRequest) { [weak self] (data,response,error) in
        if let error = error {
            print(error)
            return
        }
        if let data = data {
            DispatchQueue.main.sync {
                self?.image = UIImage(data: data)
            }
        }
    }
    task.resume()
}

更新:因为'视图模型'概念有点太多了,让我解释一下。

视图模型只是一个对象或结构,表示屏幕需要处于可显示状态的表示数据。它不是Apple定义的类型的名称,并且未在iOS SDK中的任何位置定义。这是你需要自己定义的东西。因此,在这种情况下,我建议您在将要使用它的同时将其定义为相同的文件,即与ResultsViewController在同一文件中。

你会做这样的事情:

struct ResultsViewModel {
  let title: String
  let imageURL: String
}

然后在ResultsViewController上创建一个属性,如:

var viewModel: ResultsViewModel?

或者如果您不喜欢处理选项,您可以这样做:

var viewModel = ResultsViewModel(title: "", imageURL: "")

或者,您可以执行您已经在做的事情,但我高度建议重命名这些属性。 getTitle听起来像是在做一些更多的东西,只是保持一个价值。 title会是一个更好的名字。同样的批评是getImage,另外批评它也有误导性,因为它听起来像存储图像,但事实并非如此。它存储图像网址。 imageURL是一个更好的名字。