Thread 1:signal SIGABRTの解決方法の考察

備忘録の為に非常に雑に、非常に自分勝手に書いてます。あとで暇だったら整理します

モノクロを押せばThread 1:signal SIGABRT

スクリーンショット 2016-10-03 12.09.47.png

成功したらこんな感じ

スクリーンショット 2016-10-03 13.14.47.png

 謎のエラーThread 1:signal SIGABRT、どこでバグってるのか突き止める全ての方法

手順としては、viewdidlordから一つずつ順を追っう。その際、エラーが出ないログは消していく。

2、エラーが出てる場所っぽいところでブレークポイントをつけて一つずつ進めてく

3、一つづつ進めていくとエラーが出て止まってるところで、処理が弾かれてappデリゲートのところでThread 1:signal SIGABRTが出る

appデリゲートのところでThread 1:signal SIGABRTへ飛んだその、そのポイントが、まさしくバグってるところである。

なぜ、最初っから、ここに
エラーが出てるよと教えてくれないのか。不親切である。いや、自分が馬鹿である。分かって当たり前だろと言ってるのか。?

エラーコード

import UIKit

class ViewController: UIViewController , UIImagePickerControllerDelegate, UINavigationControllerDelegate {

    @IBOutlet weak var imageView: UIImageView!

//    var originalImage: UIImage?

     //画像を編集するために画像を保持しておく変数
   var originalImage: UIImage?




    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.
    }


    @IBAction func handleTap(sender: UITapGestureRecognizer) {

        if UIImagePickerController.isSourceTypeAvailable(UIImagePickerControllerSourceType.PhotoLibrary) {
            let  ipc:UIImagePickerController = UIImagePickerController();

ipc.delegate = self

            //sourceTypeってなんすか??
            ipc.sourceType = UIImagePickerControllerSourceType.PhotoLibrary


            //presentViewControllerってなんすか??
            self.presentViewController(ipc, animated: true, completion: nil)
        }

    }




    //ImagePickerで画像が選択されたときに呼ばれる

    func imagePickerController(picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : AnyObject]) {
        if info [UIImagePickerControllerOriginalImage] != nil {

            //選択した画像を UIImageViewに設定する
            imageView.image = info[UIImagePickerControllerOriginalImage] as? UIImage

            //加工用にメンバ変数に保持
            originalImage = info[UIImagePickerControllerOriginalImage]as? UIImage
        }

        //Imageviewを閉じる
        picker.dismissViewControllerAnimated(true, completion: nil)
    }

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

    // モノクロボタンが押された時に呼ばれる
    @IBAction func pushedMonochrome(sender: UIButton) {

        guard let image = imageView.image else {

            return
        }

        let monochroImage = monochromeImages(image)

        imageView.image = monochroImage
        originalImage = monochroImage

    }

    //引数のUIImage の画像をモノクロ化した UIImageを返す
    func monochromeImages (srcImage: UIImage) -> UIImage {
    //どうしてpushedMonochromeの中に処理を書かないのだろう


        //UIImageからCIImageを作る
        let ciImage: CIImage  = CIImage(image:srcImage)!;

        //コンテキストを作成する
        let ciContext:CIContext = CIContext(options: nil)

        //フィルターを作成する
        let ciFilter:CIFilter = CIFilter(name: "CIMinimumComponent")!
        CIFilter.setValue(ciImage, forKey: kCIInputImageKey)

//フィルターを通した画像を生成する
        let cgimg:CGImageRef = ciContext.createCGImage(ciFilter.outputImage!, fromRect: ciFilter.outputImage!.extent)!


        //CGImageRefからUIImageを作成して返す
        return UIImage(CGImage: cgimg, scale: 1.0, orientation: UIImageOrientation.Up)

    }

    // スライダーの値が変わった時に呼ばれる
    @IBAction func valueChanged(sender: UISlider) {

    }

    // 保存ボタンが押された時に呼ばれる
    @IBAction func save(sender: UIButton) {

    }
}

 

正しいコード

import UIKit

class ViewController: UIViewController , UIImagePickerControllerDelegate, UINavigationControllerDelegate {

    @IBOutlet weak var imageView: UIImageView!

//    var originalImage: UIImage?

     //画像を編集するために画像を保持しておく変数
   var originalImage: UIImage?




    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.
    }


    @IBAction func handleTap(sender: UITapGestureRecognizer) {

        if UIImagePickerController.isSourceTypeAvailable(UIImagePickerControllerSourceType.PhotoLibrary) {
            let  ipc:UIImagePickerController = UIImagePickerController();
            ipc.delegate = self

            //sourceTypeってなんすか??
            ipc.sourceType = UIImagePickerControllerSourceType.PhotoLibrary


            //presentViewControllerってなんすか??したからビューだす
            self.presentViewController(ipc, animated: true, completion: nil)
        }

    }




    //ImagePickerで画像が選択されたときに呼ばれる

    func imagePickerController(picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : AnyObject]) {
        if info [UIImagePickerControllerOriginalImage] != nil {

            //選択した画像を UIImageViewに設定する
            imageView.image = info[UIImagePickerControllerOriginalImage] as? UIImage

            //加工用にメンバ変数に保持
            originalImage = info[UIImagePickerControllerOriginalImage]as? UIImage
        }

        //Imageviewを閉じる
        picker.dismissViewControllerAnimated(true, completion: nil)
    }






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

    // モノクロボタンが押された時に呼ばれる
    @IBAction func pushedMonochrome(sender: UIButton) {

        guard let image = imageView.image else {

            return
        }

        let monochroImage = monochromeImages(image)

        imageView.image = monochroImage
        originalImage = monochroImage

    }

    //引数のUIImage の画像をモノクロ化した UIImageを返す
    func monochromeImages (srcImage: UIImage) -> UIImage {
    //どうしてpushedMonochromeの中に処理を書かないのだろう


        //UIImageからCIImageを作る
        let ciImage: CIImage  = CIImage(image:srcImage)!;

        //コンテキストを作成する
        let ciContext:CIContext = CIContext(options: nil)

        //フィルターを作成する
        let ciFilter:CIFilter = CIFilter(name: "CIMinimumComponent")!
        //ここでエラーになる↓
       ciFilter.setValue(ciImage, forKey: kCIInputImageKey)

        //フィルターを通した画像を生成する
        let cgimg:CGImageRef = ciContext.createCGImage(ciFilter.outputImage!, fromRect: ciFilter.outputImage!.extent)!


        //CGImageRefからUIImageを作成して返す
        return UIImage(CGImage: cgimg, scale: 1.0, orientation: UIImageOrientation.Up)

    }

    // スライダーの値が変わった時に呼ばれる
    @IBAction func valueChanged(sender: UISlider) {

    }

    // 保存ボタンが押された時に呼ばれる
    @IBAction func save(sender: UIButton) {

    }
}

 

ブレークポイントを指定しないで止めないでエラー時点までのすべてのログを見る

止めないで最初になったエラーどこでエラー出てるか調べる.png

一つ一つのログを順を追ってみる

ViewdidLodの時に出たログ。これは動いてるから右下のゴミ箱ボタンでログを消す

ViewdidLodeの画面。左下のゴミ箱ボタンで関係のないログは消す.png

viewをタップした時のログ、ここまで動いてるからこれも消す

Viewを選んだ時に出たログ、これも関係ないから消す.png

viewに写真が出たログ

画面がviewに出た時のログ、これも正しいログなので消す.png

モノクロボタンを押した瞬間に出たログ

ここでエラーになってるから、ここらへんのログがエラーの原因

モノクロボタンを押した瞬間に出たログ.png

ログの一番上のコードを読む。

2016-10-03 12:10:32.687 ImageProcessing[29842:718409] *** Terminating app due to uncaught exception 'NSUnknownKeyException', reason: '[<CIFilter 0xc8521c> setValue:forUndefinedKey:]: this class is not key value coding-compliant for the key inputImage.'
*** First throw call stack:

 

なんとなく

key valu

key inputImage

というログに目をつけた。このコードから、ソースコード上のkey valu とかkey inputImageとかそんな感じの文字探す

見つけた、ここらへんだ

//引数のUIImage の画像をモノクロ化した UIImageを返す
    func monochromeImages (srcImage: UIImage) -> UIImage {
    //どうしてpushedMonochromeの中に処理を書かないのだろう


        //UIImageからCIImageを作る
        let ciImage: CIImage  = CIImage(image:srcImage)!;

        //コンテキストを作成する
        let ciContext:CIContext = CIContext(options: nil)

        //フィルターを作成する                       
        let ciFilter:CIFilter = CIFilter(name: "CIMinimumComponent")!

        //↓怪しい怪しい怪しい怪しい怪しい怪しい
       "CIFilter.setValue(ciImage, forKey: kCIInputImageKey)"

        //フィルターを通した画像を生成する
        let cgimg:CGImageRef = ciContext.createCGImage(ciFilter.outputImage!, fromRect: ciFilter.outputImage!.extent)!


        //CGImageRefからUIImageを作成して返す
        return UIImage(CGImage: cgimg, scale: 1.0, orientation: UIImageOrientation.Up)

    }

    // スライダーの値が変わった時に呼ばれる
    @IBAction func valueChanged(sender: UISlider) {

    }

    // 保存ボタンが押された時に呼ばれる
    @IBAction func save(sender: UIButton) {

    }
}

 

 

そもそも、モノクロボタンを押した瞬間に止まったので、ここら辺でエラーが起こってるんだろうと予測はしていた。でも、まだこの段階でなぜここでエラーになるのかわかってない

88行目、ここら辺で止める矢印を置いておく。一つ一つ処理を純追ってみていく

ここら辺で止める矢印を置いておく.png

1個目動いてる

1個目動いてる.png

2個目、93行目、動いてる

2個目、93行目、動いてる.png

95行め動いてる。はい、次で止まります

95行め動いてる。はい、次で止まります.png

 

//ここでエラーになる↓
       CIFilter.setValue(ciImage, forKey: kCIInputImageKey)

 

はい、ここまでは来ていました。ここで次へ行くと死にます。つまり、ここから先の処理に行けない。このコードが間違ってるよと言われました。なぜ、どこが間違っているのでしょうか。よく見てみる

ここら辺をよく見て発見する

//UIImageからCIImageを作る
       let ciImage: CIImage  = CIImage(image:srcImage)!;

       //コンテキストを作成する
       let ciContext:CIContext = CIContext(options: nil)

       //フィルターを作成する
       let ciFilter:CIFilter = CIFilter(name: "CIMinimumComponent")!
       //ここでエラーになる↓
      CIFilter.setValue(ciImage, forKey: kCIInputImageKey)

       //フィルターを通した画像を生成する
       let cgimg:CGImageRef = ciContext.createCGImage(ciFilter.outputImage!, fromRect: ciFilter.outputImage!.extent)!


 

 

バカな、型に代入しているじゃないか、俺は

 

//フィルターを作成する
        let ciFilter:CIFilter = CIFilter(name: "CIMinimumComponent")!
        //ここでエラーになる↓
       CIFilter.setValue(ciImage, forKey: kCIInputImageKey)

 

 

型にアクセスなんかできない。ちゃんと変数に代入させてアクセス

//フィルターを作成する
        let ciFilter:CIFilter = CIFilter(name: "CIMinimumComponent")!
        //ここでエラーになる↓
       ciFilter.setValue(ciImage, forKey: kCIInputImageKey)

 

詳しくはteratailにも質問した

https://teratail.com/questions/50050

藤沢瞭介(Ryosuke Hujisawa)
  • りょすけと申します。18歳からプログラミングをはじめ、今はフロントエンドでReactを書いたり、AIの勉強を頑張っています。off.tokyoでは、ハイテクやガジェット、それからプログラミングに関する情報まで、エンジニアに役立つ情報を日々発信しています!

未整理記事