Destination Controller
class CharDetailsViewController: UIViewController {
@IBOutlet weak var imageView: UIImageView!
@IBOutlet weak var nameLabel: UILabel!
@IBOutlet weak var genderLabel: UILabel!
@IBOutlet weak var houseLabel: UILabel!
@IBOutlet weak var ancestryLabel: UILabel!
var image = UIImage()
var name = String()
var gender = String()
var house = String()
var ancestry = String()
override func viewDidLoad() {
super.viewDidLoad()
imageView.image = image
nameLabel.text! = name
houseLabel.text! = house
// Do any additional setup after loading the view.
}
Source Controller
class CharacterTableViewController: UITableViewController {
var charactersData = [Character]()
override func viewDidLoad() {
super.viewDidLoad()
loadData()
}
func loadData()
{
DispatchQueue.main.async {
Alamofire.request("http://hp-api.herokuapp.com/api/characters").responseJSON(completionHandler: {
(response) in
switch response.result
{
case.success(let value):
let json = JSON(value)
print(json)
json.array?.forEach({
(character) in
let character = Character(name: character["name"].stringValue, house:character["house"].stringValue,image:character["image"].stringValue, gender: character["gender"].stringValue, ancestry: character["ancestry"].stringValue)
self.charactersData.append(character)
})
self.tableView.reloadData()
case.failure(let error):
print(error.localizedDescription)
}
})
}
}
override func tableView( tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return charactersData.count
}
override func tableView( tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! CharTableViewCell
cell.nameLabel.text = "Name: " + charactersData[indexPath.row].name
cell.houseLabel.text = "House: " + charactersData[indexPath.row].house
if let imageURL = URL(string: self.charactersData[indexPath.row].image) {
DispatchQueue.global().async {
let data = try? Data(contentsOf: imageURL)
if let data = data {
let image = UIImage(data: data)
DispatchQueue.main.async {
cell.charImageView.image = image
}
}
}
}
return cell
}
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let hpc = storyboard?.instantiateViewController(withIdentifier: "CharDetails") as? CharDetailsViewController
hpc?.image = UIImage(named: charactersData[indexPath.row].image)! //Error found here
hpc?.name = charactersData[indexPath.row].name
hpc?.house = charactersData[indexPath.row].house
self.navigationController?.pushViewController(hpc!, animated: true)
}
class Character
{
var name : String
var house : String
var image : String
init(name: String, house: String, image: String)
{
self.name = name
self.house = house
self.image = image
}
}
I'm getting a unexpectedly found nil while unwrapping an optional value image for passing the image to another controller. I have checked the outlets and they are perfectly fine. The images are grabbed from a url array as JSON Format as shown above, they are working fine on the table view and seen on the table view, but they are not showing up on the details view page. Kindly please assist me.
You are trying to forcefully unwrap UIImage, which is nil. UIImage(named:)
method is used when the image is present inside the bundle and you wants to show it from there.
hpc?.image = UIImage(named: charactersData[indexPath.row].image)! //Error found here
On the above line, you are using UIImage(named:)! which means, you are force unwrapping it, that leads to crash with unexpectedly found nil while unwrapping an optional value
Solution You can pass the image name same as the name and house,
1) Update your
class CharDetailsViewController: UIViewController {
// Add this property to hold url string for image.
var imageUrlString = String()
}
2) in didSelectRow, update the code to pass the imageUrlString
hpc?.imageUrlString = charactersData[indexPath.row].image
2) put this in your viewDidLoad method of CharDetailsViewController
if let imageURL = URL(string: imageUrlString) {
DispatchQueue.global().async {
let data = try? Data(contentsOf: imageURL)
if let data = data {
let image = UIImage(data: data)
DispatchQueue.main.async {
self.imageView.image = image
}
}
}
}
Hope it helps