0

I have created an App using xcode 10 and use swift 4.

I am getting an error:

Fatal error: Unexpectedly found nil while unwrapping an Optional value`

I started to use NavigationController, and now I get an error. When doing Segue in the state before use, no error occurred. I checked for Typo's etc, but there is no problem.

Error is this part

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {

    let cell = UITableViewCell()

    switch indexPath.section {
    case 0 :
    //Price Cell
    let priceCell = tableView.dequeueReusableCell(withIdentifier: "priceCell", for: indexPath) as? priceTableViewCell

    //Fatal error: Unexpectedly found nil while unwrapping an Optional value
    if let price:String = store![indexPath.row].price{
        priceCell?.priceLabel.text! = price
    }else{
        priceCell?.priceLabel.text! = "-"
    }
    return priceCell!

    case 1 :
    //timeCell

        let timeCell = tableView.dequeueReusableCell(withIdentifier: "timeCell", for: indexPath) as? timeTableViewCell

        if let time:String = store![indexPath.row].open_time{
            timeCell?.timeLabel.text! = time
        }else{
            timeCell?.timeLabel.text! = "-"
        }
    return timeCell!

    case 2 :
    //closedayCell
    let closedayCell = tableView.dequeueReusableCell(withIdentifier: "closedayCell", for: indexPath) as? closedayTableViewCell

    if let closeday:String = store![indexPath.row].closed_day{
        closedayCell?.closedayLabel.text! = closeday
    }else{
        closedayCell?.closedayLabel.text! = "-"
    }


    return closedayCell!

    default :
        print("Default Selected")
    }
    return cell
}

Store View Controller All view

import UIKit

class StoreViewController: 
    UIViewController,UICollectionViewDataSource,UICollectionViewDelegate,  
    UICollectionViewDelegateFlowLayout,UITableViewDelegate, 
    UITableViewDataSource {


    var store_id = ""
    var store : [Store]?
    var photoPath : [Store.photos]?
    var tag : [Store.tags]?
    var selectedImage : UIImage?
    let defaultValues = UserDefaults.standard


    @IBOutlet weak var imageCollectionView: UICollectionView!
    @IBOutlet weak var mainImage: UIImageView!
    @IBOutlet weak var nameLabel: UILabel!
    @IBOutlet weak var locationLabel: UILabel!
    @IBOutlet weak var UIView: UIView!
    @IBOutlet weak var tagCollectionView: UICollectionView!
    @IBOutlet weak var tableView: UITableView!


    override func viewDidLoad() {
        super.viewDidLoad()


        //Collectiopn DetaSources
        imageCollectionView.dataSource = self
        imageCollectionView.delegate = self

        tagCollectionView.dataSource = self
        tagCollectionView.delegate = self

        //UIView Shadow
        let shadowPath = UIBezierPath(rect: UIView.bounds)
        UIView.layer.masksToBounds = false
        UIView.layer.shadowColor = UIColor.black.cgColor
        UIView.layer.shadowOffset = .zero
        UIView.layer.shadowOpacity = 0.2
        UIView.layer.shadowPath = shadowPath.cgPath

        //Request API
        let url = URL(string: "http://localhost:8000/store/api?store_id=" + store_id)
        let request = URLRequest(url: url!)
        let session = URLSession.shared

        let encoder: JSONEncoder = JSONEncoder()
        encoder.dateEncodingStrategy = .iso8601
        encoder.outputFormatting = .prettyPrinted

        session.dataTask(with: request){(data, response, error)in if error == nil,
            let data = data,
            let response = response as? HTTPURLResponse{

            let decoder: JSONDecoder = JSONDecoder()
            decoder.dateDecodingStrategy = .iso8601
            do {

                let json = try decoder.decode(Store.self, from: data)

                if json != nil {
                    print(json)
                }else{
                    print("nil")
                }
                self.store = [json]
                self.photoPath = json.photos
                self.tag = json.tags

                if let imageURL = URL(string: "http://127.0.0.1:8000/photos/" + json.photos[0].path){
                    DispatchQueue.global().async {
                        let data = try? Data(contentsOf: imageURL)
                        if let data = data {
                            let image = UIImage(data: data)
                            DispatchQueue.main.async {
                                self.mainImage.image = image
                            }
                        }
                    }
                }

                DispatchQueue.main.async {
                    self.nameLabel.text = json.name
                    self.locationLabel.text = json.location

                }

            } catch {
                print("error:", error.localizedDescription)

            }

            }

            }.resume()

        //print(defaultValues.string(forKey: "id"))


        // Image Collection view Layout
        let itemSize = UIScreen.main.bounds.width/3.62 - 3.62

        let layout = UICollectionViewFlowLayout()

        layout.sectionInset = UIEdgeInsetsMake(0, 0, 0, 0)
        layout.itemSize = CGSize(width: itemSize, height: itemSize)

        layout.minimumInteritemSpacing = 1
        layout.minimumLineSpacing = 1

        imageCollectionView.collectionViewLayout = layout

        // Tag Collection View
        let tagLayout = UICollectionViewFlowLayout()

        tagLayout.minimumLineSpacing = 1
        tagLayout.minimumInteritemSpacing = 1
        tagLayout.sectionInset = UIEdgeInsetsMake(0, 0, 0, 0)
        tagLayout.itemSize = CGSize(width: 80, height: 24)
        tagCollectionView.collectionViewLayout = tagLayout

        print("storeID is"+store_id)
    }


    override func viewDidAppear(_ animated: Bool) {
        super.viewDidAppear(animated)
    //        UI coner redius
        let uiViewPath = UIBezierPath(roundedRect: UIView.bounds, 
        byRoundingCorners: [.topLeft, .topRight], cornerRadii: CGSize(width: 8, height: 8))
        let uiViewMask = CAShapeLayer()
        uiViewMask.path = uiViewPath.cgPath
        UIView.layer.mask = uiViewMask

    }


    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }

    //Collection
       func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
        if collectionView == self.imageCollectionView{
            let imageCell:UICollectionViewCell = collectionView.dequeueReusableCell(withReuseIdentifier: "Cell",for: indexPath)
            let imageView = imageCell.contentView.viewWithTag(1) as! UIImageView

            let imageURL = URL(string: "http://127.0.0.1:8000/photos/" + photoPath![indexPath.row].path)
            if imageURL == nil {
                print("nil")
            }else{
                DispatchQueue.global().async {
                    let data = try? Data(contentsOf: imageURL!)
                    if let data = data {
                        let image = UIImage(data: data)
                        DispatchQueue.main.async {
                            imageCell.layer.masksToBounds = true;
                            imageCell.layer.cornerRadius = 3
                            imageView.image = image
                        }
                    }
                }
            }


            return imageCell

         //Tag collection view
        }else if collectionView == self.tagCollectionView{
            let tagCell:UICollectionViewCell = collectionView.dequeueReusableCell(withReuseIdentifier: "Tag",for: indexPath)
            let tagLabel = tagCell.contentView.viewWithTag(2) as! UILabel

                tagLabel.text! = tag![indexPath.row].name

            tagCell.layer.cornerRadius = 12
            return tagCell


        }else{
        return UICollectionViewCell()
    }
    }




    func numberOfSections(in collectionView: UICollectionView) -> Int {
        return 1
    }

    func collectionView(_ collectionView: UICollectionView,
                        numberOfItemsInSection section: Int) -> Int {
        return 3
    }


    func tagcollectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
        return tag?.count ?? 0
    }

    func numberOfSections(in tableView: UITableView) -> Int {
        return 3
    }

    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {

        switch section {
        case 0:
            return 1
        case 1 :
            return 1
        case 2 :
            return 1
        default:
            return 0
        }
    }


    //Collection view tap
    func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
        if collectionView == self.imageCollectionView{
            if photoPath![indexPath.row].path != nil {
                if let imageURL = URL(string: "http://127.0.0.1:8000/photos/" + photoPath![indexPath.row].path ){
                    DispatchQueue.global().async {
                        let data = try? Data(contentsOf: imageURL)
                        if let data = data {
                            let image = UIImage(data: data)
                            DispatchQueue.main.async {
                                self.mainImage.image = image
                            }
                        }
                    }
                }
            }else{
                print("error")
                return
            }
        }
    }

    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {

        let cell = UITableViewCell()

        switch indexPath.section {
        case 0 :
        //Price Cell
        let priceCell = tableView.dequeueReusableCell(withIdentifier: "priceCell", for: indexPath) as? priceTableViewCell

        if let price:String = store![indexPath.row].price{
            priceCell?.priceLabel.text! = price
        }else{
            priceCell?.priceLabel.text! = "-"
        }
        return priceCell!

        case 1 :
        //timeCell

            let timeCell = tableView.dequeueReusableCell(withIdentifier: "timeCell", for: indexPath) as? timeTableViewCell

            if let time:String = store![indexPath.row].open_time{
                timeCell?.timeLabel.text! = time
            }else{
                timeCell?.timeLabel.text! = "-"
            }
        return timeCell!

        case 2 :
        //closedayCell
        let closedayCell = tableView.dequeueReusableCell(withIdentifier: "closedayCell", for: indexPath) as? closedayTableViewCell

        if let closeday:String = store![indexPath.row].closed_day{
            closedayCell?.closedayLabel.text! = closeday
        }else{
            closedayCell?.closedayLabel.text! = "-"
        }

        return closedayCell!

        default :
            print("Default Selected")
        }
        return cell
    }

    @IBAction func moreImageBtn(_ sender: Any) {
        let store_id = self.store_id
        self.performSegue(withIdentifier: "toStorePhotoViewController", sender: store_id)
    }

    override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
        if segue.identifier == "toStorePhotoViewController"{
            let storePhotoViewController = segue.destination as! StorePhotoViewController
            storePhotoViewController.store_id = sender as! String
        }
    }

    //Bookmark Button
    @IBAction func bookmarkBtn(_ sender: Any) {
        let user_id = defaultValues.string(forKey: "userId")
        let url = URL(string: "http://localhost:8000/api/store/favorite?")
        var request = URLRequest(url: url!)
        // POSTを指定
        request.httpMethod = "POST"
        // POSTするデータをBodyとして設定
        let postParameters = "user_id=" + user_id! + "&store_id=" + store_id
        request.httpBody = postParameters.data(using: .utf8)
        let session = URLSession.shared
        session.dataTask(with: request) { (data, response, error) in
            if error == nil, let data = data, let response = response as? HTTPURLResponse {
                // HTTPヘッダの取得
                print("Content-Type: \(response.allHeaderFields["Content-Type"] ?? "")")
                // HTTPステータスコード
                print("statusCode: \(response.statusCode)")
                print(String(data: data, encoding: .utf8) ?? "")
            }
        }.resume()
    }

    @IBAction func locationBtn(_ sender: Any) {
        let lat = store![0].lat
        let lng = store![0].lng

        if UIApplication.shared.canOpenURL(URL(string:"comgooglemaps://")!){
            let urlStr : String = "comgooglemaps://?daddr=\(lat),\(lng)&directionsmode=walking&zoom=14"
            UIApplication.shared.open(URL(string:urlStr)!,options: [:], completionHandler: nil)
        }else{
            let daddr = String(format: "%f,%f", lat, lng)
            let urlString = "http://maps.apple.com/?daddr=\(daddr)&dirflg=w"
            let encodeUrl = urlString.addingPercentEncoding(withAllowedCharacters:NSCharacterSet.urlQueryAllowed)!

            let url = URL(string: encodeUrl)!
            UIApplication.shared.open(url,options: [:], completionHandler: nil)
        }
    }
}
Scriptable
  • 19,402
  • 5
  • 56
  • 72
Alex
  • 71
  • 2
  • 9

2 Answers2

0

As mentioned by @Scriptable, You should not force unwrap.

You can add Exception break point for break point navigator like below enter image description here

And then enter image description here

This will help to pin point issue, Hopefully.

Abdul Rehman
  • 2,386
  • 1
  • 20
  • 34
0

Declare array as below

var store = [Store]()

Change TableView datasource as per below:

func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {

        switch section {
        case 0:
            return store.count > 0 ? 1 : 0 // if array count greater than return 1 else 0
        case 1 :
            return store.count > 0 ? 1 : 0
        case 2 :
            return store.count > 0 ? 1 : 0
        default:
            return 0
        }
    }
KKRocks
  • 8,222
  • 1
  • 18
  • 84