web-dev-qa-db-ja.com

UITableViewAlertForLayoutOutsideViewHierarchyエラー:1回だけ警告(iOS 13 GM)

セグエを実行するとiOS13で奇妙なエラーが発生し、それが何を意味するのか理解できません。また、このエラーのドキュメントも見つかりません。問題は、これにより、セグエが実行されるまでに多くの遅延(数秒)が発生するように見えることです。

2019-09-11 22:45:38.861982 + 0100 Thrive [2324:414597] [TableView]警告1回のみ:UITableViewは、ビュー階層(テーブルビューまたはそのいずれか)に表示されずに、表示されているセルとその他のコンテンツをレイアウトするように指示されましたスーパービューはウィンドウに追加されていません)。これにより、正確な情報(例:テーブルビューの境界、特性コレクション、レイアウトマージン、セーフエリアインセットなど)なしでテーブルビュー内のビューに強制的にレイアウトをロードして実行することでバグが発生する可能性があり、追加のレイアウトパスにより不要なパフォーマンスオーバーヘッドが発生します。 。 UITableViewAlertForLayoutOutsideViewHierarchyにシンボリックブレークポイントを作成してデバッガでこれをキャッチし、これが発生した原因を確認します。これにより、可能な場合はこのアクションを完全に回避するか、テーブルビューがウィンドウに追加されるまで延期できます。テーブルビュー:;レイヤー=; contentOffset:{0、0}; contentSize:{315、118}; AdjustedContentInset:{0、0、0、0}; dataSource:>

私はヒーローを使用していますが、それを無効にして通常のセグエを使用してみましたが、これで遅延が解消されませんでした。

セグエを開始するコードはdidSelectRowAtです

func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
        if indexPath.section == 0 {
            selectedCell = realIndexFor(activeGoalAt: indexPath)
            performSegue(withIdentifier: "toGoalDetails", sender: nil)
        } else if indexPath.section == 1 {
            selectedCell = indexPath.row
            performSegue(withIdentifier: "toIdeaDetails", sender: nil)
        } else {
            selectedDecision = indexPath.row
            hero(destination: "DecisionDetails", type: .zoom)
        }
    }

そして、宛先からのviewDidLoadまたはviewWillAppearのコードはどれもVCはこれに何らかの影響を与えません(私は違いなくすべてをコメントアウトしてみました。

これを引き起こしているものは何ですか?他に必要な詳細はすべて共有できます。

ありがとうございました。

17
CristianMoisei

これは、viewWillAppear(:)メソッドでデバイスを向き変更通知用に登録したためです。viewDidAppear( :)で登録を移動し、Xcodeがブレークポイントで停止しなくなりました。

私が言えることは、ビューがすでに表示されているときにレイアウト変更が実行される可能性があるということです...

9
Miniapps

iPadOS 13.2.3 Swift 5.2 Xcode 11.2.1

デバイスが横向きのときにアプリを起動したときにのみ、この問題が発生しました。詳細ビューが正しく設定されていることを確認するために、マスターコントローラーのviewDidLoad funcで詳細シークを呼び出していました。

     override func viewDidLoad() {
       super.viewDidLoad()
            ...
       self.performSegue(withIdentifier: "showDetail", sender: self)
     }

performSequeを削除すると、警告は表示されなくなりましたが、詳細コントローラーの左バーボタンは正しく機能しなくなりました。これも、デバイスが横長の状態でアプリを起動した場合のみです。一番左のボタンは、最初のボタンが想定していたものではなく、右側の次のボタンをアクティブにします。

バーボタンの修正は、viewDidLoadに追加することでした。

     override func viewDidLoad() {
       super.viewDidLoad()
            ...
       self.splitViewController?.preferredDisplayMode = UISplitViewController.DisplayMode.allVisible
     }

次に実行します

     override func viewWillAppear(_ animated: Bool) {
       self.splitViewController?.preferredDisplayMode = UISplitViewController.DisplayMode.automatic
       super.viewWillAppear(animated)
     }

なぜこれがうまくいったのか私には説明がありません!

このアプリは、iPados 13がロードされるまで問題なく動作しました。

2
Daryl1109

私はXcode/Swiftを初めて使用するので、これはだれにも役に立たないかもしれません。詳細ビューからリストに戻ると、アプリ内でiOS 13およびXcode 11に更新した後、このエラーが発生し始めました。

巻き戻しで_tableView.reloadRows_および_tableView.insertRows_を実行していることがわかりました(Apple in one of your tutorials

_@IBAction func unwindToMealList(sender: UIStoryboardSegue) {
    if let sourceViewController = sender.source as? MealViewController, let meal = sourceViewController.meal {

        if let selectedIndexPath = tableView.indexPathForSelectedRow {
            // Update an existing meal.
            meals[selectedIndexPath.row] = meal
            tableView.reloadRows(at: [selectedIndexPath], with: .none)
        }
        else {
            // Add a new meal.
            let newIndexPath = IndexPath(row: meals.count, section: 0)

            meals.append(meal)
            tableView.insertRows(at: [newIndexPath], with: .automatic)
        }
    }
}

)
_

私はコードのそのセクションをコメントアウトし、それは消えました。

奇妙なことに、ソートを残してself.tableView.reloadData()を実行してもエラーは発生しませんでした。

2
Joe H.

@ joe-hのように、私はこのエラーを受け取り、上に示したアンワインドアプローチが多くの開発者によって使用されているものであることにも驚きました+いくつかの重要なApple iOSサンプルコードにあります.

私のコードのトリガー行(@ joe-h、私もあなたのものだと思います)は、selectedIndexPathのtableView.reloadRows(ラップされていないtableView.indexPathForSelectedRow)です。

tableView.reloadRows(at: [selectedIndexPath], with: .automatic)

残念ながら、既存のtableView行の値を更新した後で巻き戻す場合は、行をコメント化することはできません(これは、上記のApple FoodTrackerチュートリアルのアプローチであり、 AppleのEveryone Can Codeシリーズです。行をリロードしないと、変更はtableViewに表示されません。アンワインドでリロードをコメントアウトした後、次のコードでviewDidAppearを追加しましたが、これは物事を修正する:

override func viewDidAppear(_ animated: Bool) {
    super.viewDidAppear(animated)
    if let selectedIndexPath = tableView.indexPathForSelectedRow {
        tableView.reloadRows(at: [selectedIndexPath], with: .automatic)
    }
}

これが健全なアプローチであるかどうかについてのコメントを歓迎しますが、今のところ、これはうまくいくようです。

2
Gallaugher
extension UIView {

  func rootView() -> UIView {
     var view = self
     while view.superview.isNotNil {
         view = view.superview!
     }
     return view
  }

  var isOnWindow: Bool {
     return self.rootView() is UIWindow
    }
  }

次に、あなたのtableViewがisOnWindowのようかどうかを確認するだけです...

if self.tableView.isOnWindow {
/// do stuff
}

免責事項:ドキュメントで説明されているように、呼び出しを延期する必要がある場合があります。つまり、メソッドが再度呼び出される保証がないため、isOnWindowがtrueのときに更新を実行する必要があります。

1
James Rochabrun

SwiftUIで同様のブレークポイントを取得していますが、viewDidLoadやviewDidappearも処理していません

    //
//  ContentView.Swift
//  DD
//
//  Created by Roman Emperor on 3/29/20.
//  Copyright © 2020 Emperors. All rights reserved.
//
import Combine
import SwiftUI

// Defining a class Booking of type Bindable Object [changed to ObservableObject]
class Booking: ObservableObject {
    var didChange = PassthroughSubject<Void, Never>()

    // Array of types to work with
    static let types = ["Consultation", "Tooth Pain", "Cleaning", "Brases", "Dental Implant" ]
    // Setting instance varibale type
    var type = 0 { didSet { update() } }

    func update () {
        didChange.send(())
    }
}


struct ContentView: View {
    @ObservedObject var booking = Booking() //bindableObject in old Swift version

    var body: some View {
        NavigationView {
            Form {
                Section {
                    Picker(selection: $booking.type, label: Text("Select a Booking Type")) {
                        ForEach(0 ..< Booking.types.count){
                            Text(Booking.types[$0]).tag($0)
                        }
                    }
                }
            }
        .navigationBarTitle(Text("Darpan Dental Home"))
        }
    }
}


struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}

完全な出力ログはここにあります:

*> 2020-03-29 09:22:09.626082 + 0545 DD [1840:76404] [TableView]警告

1回のみ:UITableViewは、ビュー階層にない状態でその可視セルと他のコンテンツをレイアウトするように指示されました(tテーブルビューまたはそのスーパービューの1つがウィンドウに追加されていません)。これにより、テーブルビュー内のビューに、正確な情報(例:テーブルビューの境界、特性コレクション、レイアウトマージン、セーフエリアインセットなど)を読み込まずにレイアウトを実行させると、バグが発生する可能性があり、追加のレイアウトパスにより、不要なパフォーマンスオーバーヘッドが発生します。 UITableViewAlertForLayoutOutsideViewHierarchyにシンボリックブレークポイントを作成して、デバッガでこれをキャッチし、これが発生した原因を確認します。これにより、可能であればこのアクションを完全に回避するか、延期できます。テーブルビューがウィンドウに追加されるまで、それを繰り返します。*

** SwiftUIのこのUITableViewAlertForLayoutOutsideViewHierarchyはどこにありますか? **

0
Parajuli Roman