カテゴリー
SugiBlog ホームページ制作・システム開発|大阪

iOS13で発生するクラッシュ NSInternalInconsistencyException

GoogleMapを使用したiOSアプリを使っていて、地図を表示しているときに急にクラッシュするようになったので原因を調べました。
発生するエラーの内容は以下の通り

Fatal Exception: NSInternalInconsistencyException
Modifications to the layout engine must not be performed from a background thread after it has been accessed from the main thread.

iOS13で内部仕様が変わったことによるもののようです。

どうもバックグラウンドスレッドからUIを触るなということらしいですが、
そんなことはしていないつもりでした。
おそらくこれまでよりも厳密になったのでしょうか…。
とにかく対応するしかありません。

元のソースコード

let session = URLSession(configuration: URLSessionConfiguration.default)

let task = session.dataTask(with: URLRequest(url: Foundation.URL(string: url)!), completionHandler: { (data, response, error) in
    if let urlContent = data {
        print(urlContent)
    }
})
task.resume()

修正したコード

let session = URLSession(configuration: URLSessionConfiguration.default)

let task = session.dataTask(with: URLRequest(url: Foundation.URL(string: url)!), completionHandler: { (data, response, error) in
    if let urlContent = data {
        DispatchQueue.main.sync {
            print(urlContent)
        }
    }
})
task.resume()
0
176 views

Realm.addでコンパイルエラー

Realm.addメソッドで以下のようなコンパイルエラーが出ました。

'add(_:update:)' is unavailable: Pass .error, .modified or .all rather than a boolean. .error is equivalent to false and .all is equivalent to true.

どうやら第2引数にbool値を与える仕様が変わった模様。
第2引数に与える値はRealm.UpdatePolicyだそうで、
これまでfalseにしていた場合は.error、trueにしていた場合は.allを指定すればいいようです。

Xcode 11.2.1
Swift 5

0
216 views

JSONデータをCodableを使って構造化する

JSONデータを解析するためにJSONSerializerを使っていましたが、Swift4からもっと簡単にできるようになったのでやってみました。

CodableというプロトコルがSwift4から新たに追加されました。
これを利用すれば簡単に構造体に落とし込むことができます。

まずはデータを扱う構造体を宣言します。
Codableと付け加えましょう。

struct myData: Codable {
    
    let ID_C: Int
    let NAME_C: String
    let COMMENT_C: String? //nullを許容
    let DATE_C: String

}

次にWEB上からデータを取得するため、URLSessionを使用します。

let session = URLSession(configuration: URLSessionConfiguration.default)
let url = "http://www.example.jp/json.php" //JSONデータを取得するURL

単純に文字列で出力してみましょう。 続きを読む…»

0
1,344 views

図形を描画して内部の面積を計測する

iOSアプリ上のGoogleMapで図形を描画し、そのパス内部の面積を計測することができます。

まずは図形を描画します。

// Create a rectangular path
let rect = GMSMutablePath()
rect.add(CLLocationCoordinate2D(latitude: 37.36, longitude: -122.0))
rect.add(CLLocationCoordinate2D(latitude: 37.45, longitude: -122.0))
rect.add(CLLocationCoordinate2D(latitude: 37.45, longitude: -122.2))
rect.add(CLLocationCoordinate2D(latitude: 37.36, longitude: -122.2))

// Create the polygon, and assign it to the map.
let polygon = GMSPolygon(path: rect)
polygon.fillColor = UIColor(red: 0.25, green: 0, blue: 0, alpha: 0.05);
polygon.strokeColor = .black
polygon.strokeWidth = 2
polygon.map = mapView

面積を計測

let a: Double = GMSGeometryArea(polygon.path!)

JavaScriptのAPIではパスが閉じている必要がありましたが、
こちらは閉じていなくても閉じているものと仮定してくれるようです。

ただ、実際に使ってみた結果、JavaScript APIのほうで測った面積と24m²ほど差がありました。

JavaScriptでの計測はこちら→GoogleMapで面積計測(v3)

Xcode: 9.4.1
Swift: 3.3
OS: High Sierra 10.13.6

0
609 views

ナビゲーションバーのタイトルを変更

UINavigationControllerのタイトルを動的に変更することができます。
短いですが、メモ的に。

// タイトルをセット
self.navigationItem.title = "テストタイトル"

Xcode: 9.4.1
Swift: 3.3
OS: High Sierra 10.13.6

0
598 views

Swift 文字列を分割する

Swiftで文字列を分割して配列に格納する方法をご紹介します。
Foundationのインポートが必要です。

let myString: String = "2018/02/15"
var myArray: [String]
myArray = myString.components(separatedBy: "/")
0
1,221 views

Xcode 9 アップデートの対応

Xcode 9 Swift 4がリリースされたので、アップデートしてみました。
その際のマイグレーションについて参考になるかは分かりませんが、
私が開発しているアプリでの作業をメモしておきます。

今回のアプリはGoogleMapsとRealm、SVProgressHUDを使用したアプリですので
そのAPIパッケージもアップグレードする必要があります。

ターミナルでプロジェクトのディレクトリに移動します。

cd <path-to-project>

pod updateを実行します。

pod update

インストールしていたAPIがアップグレードされます。
iOSのターゲットを9.0としていたため、エラーが解消されなかったのでターゲットを10.0に変更しました。

Xcodeでプロジェクトを開くと色々と警告が表示されていました。

ビルドしてももちろん通らないので、修正をしていきます。
続きを読む…»

0
1,855 views

UIViewのアニメーション

今回はUIViewやUIButtonをアニメーションさせる方法をご紹介します。

まずはアニメーションさせる適当なViewを作成します。

let sampleView = UIView()

sampleView.frame.size = CGSize(width: 120, height: 120)
sampleView.center = CGPoint(x: 60, y: 60)
sampleView.backgroundColor = UIColor.white
sampleView.layer.borderColor = UIColor.cyan.cgColor
sampleView.layer.borderWidth = 2

view.addSubview(sampleView)

作成したViewをアニメーションさせるにはUIView.animateメソッドを使用します。
ここでは大きさを変更してみましょう。
中心点も設定しているのは、大きさを変更すると左上を起点に大きさが変わってしまうためです。

UIView.animate(withDuration: 0.5, animations: {
    self.sampleView.frame.size = CGSize(width: 80, height: 80)
    self.sampleView.center = CGPoint(x: 60, y: 60)
}, completion: { Void in
    // アニメーション完了時の処理を記述します
})

次に、大きさと角丸の半径をアニメーションで変更してみたいと思います。
サンプルとして、標準カメラアプリの動画撮影ボタンのようなボタンを作成してみましょう。
実際の撮影処理はしていません。

まずは必要な宣言

let shutterView = UIView()
let shutterButton = UIButton()
var isRecording: Bool = false

Viewを作成するメソッドを作成します。

func makeShutterView() {
    shutterView.frame.size = CGSize(width: 74, height: 74)
    shutterView.center = CGPoint(x: 45, y: 45)

    let shutterCircle = UIView()
    shutterCircle.frame.size = CGSize(width: 76, height: 76)
    shutterCircle.center = CGPoint(x: 45, y: 45)
    shutterCircle.layer.borderColor = UIColor.white.cgColor
    shutterCircle.layer.borderWidth = 4
    shutterCircle.layer.cornerRadius = 38.0
    shutterView.addSubview(shutterCircle)

    shutterButton.frame.size = CGSize(width: 60, height: 60)
    shutterButton.center = CGPoint(x: 45, y: 45)
    shutterButton.backgroundColor = UIColor.red
    shutterButton.layer.cornerRadius = 30.0
    shutterButton.addTarget(self, action: #selector(onClickRecordingButton), for: .touchUpInside)
    shutterView.addSubview(shutterButton)

    view.addSubview(shutterView)
}

続きを読む…»

0
1,432 views

UISearchControllerの警告

UISearchControllerを使っていると、ViewControllerが破棄されるタイミングで以下のような警告が出てきました。

[Warning] Attempting to load the view of a view controller while it is deallocationg is not allowed and may result in undefined behavior (<UISearchController: ...>)

どうやらViewControllerが破棄されるタイミングでSearchControllerも破棄してやらないといけないようです。

以下のコードを追加したら解決しました。

deinit {
    searchController.view.removeFromSuperview()
}

また、実際に検索をして別画面に遷移した際に、UISearchControllerの表示が残ったままになる問題が発生しました。
キャンセルをタップすれば消すことができますが、それでは気持ちが悪いので解決させたい。
解決方法は遷移元のUIViewControllerのviewDidonLoadに以下の1行を追加するだけです。

definesPresentationContext = true

私の場合、原因はUINavigationControllerを使っていたことでした。

こちらで詳しく解説されています。
参考URL: http://qiita.com/color_box/items/d13b04a88587088019af

Xcode: 8.3.2
Swift: 3.1
OS: Sierra 10.12

0
1,032 views

UITableView スワイプでセルを削除する

簡単に実装できるので楽ですね。

UITableViewをOutlet接続しておきます。

@IBOutlet weak var table: UITableView!

削除処理の実装

func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCellEditingStyle, forRowAt indexPath: IndexPath) {
    if editingStyle == .delete {
        table.deleteRows(at: [indexPath], with: .fade)
    }
}

Xcode: 8.3.2
Swift: 3.1
OS: Sierra 10.12

0
2,058 views