Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Track and fix swiftUI crash (saw PreferenceKeys, expected ViewList)?

Tags:

xcode

swiftui

I'm getting a crash when I move quickly in my app (open a sub-page then go back to landing).

App crash log from TestFlight:

App crash log from TestFlight

Thread 0 name:
Thread 0 Crashed:
0   libsystem_kernel.dylib          0x00000001c87ff334 __pthread_kill + 8
1   libsystem_pthread.dylib         0x00000001e6221aa0 pthread_kill + 272 (pthread.c:1392)
2   libsystem_c.dylib               0x00000001a3b86c10 __abort + 116 (abort.c:147)
3   libsystem_c.dylib               0x00000001a3b86b9c abort + 116 (abort.c:118)
4   AttributeGraph                  0x00000001c3c31a6c AG::precondition_failure(char const*, ...) + 192 (ag-util.cc:51)
5   AttributeGraph                  0x00000001c3c1f4cc AG::Graph::input_value_ref_slow(AG::data::ptr<AG::Node>, AG::AttributeID, unsigned int, AGSwiftMetadata const*, bool*, long) + 828 (ag-graph.cc:0)
6   AttributeGraph                  0x00000001c3c3109c AGGraphGetValue + 232 (ag-graph-impl.h:43)
7   SwiftUI                         0x00000001a140bbc4 AnyViewList.Item.list.getter + 72 (<compiler-generated>:0)
8   SwiftUI                         0x00000001a140b5e8 AnyViewList.updateValue() + 512 (AnyView.swift:333)
9   SwiftUI                         0x00000001a0f1f0c4 partial apply for specialized implicit closure #2 in implicit closure #1 in closure #1 in closure #1 in Attribute.init<A>(_:) + 24 (<compiler-generated>:0)
10  AttributeGraph                  0x00000001c3c1977c AG::Graph::UpdateStack::update() + 492 (ag-closure.h:108)
11  AttributeGraph                  0x00000001c3c19bb4 AG::Graph::update_attribute(AG::data::ptr<AG::Node>, bool) + 332 (ag-graph-update.cc:563)
12  AttributeGraph                  0x00000001c3c22dc4 AG::Subgraph::update(unsigned int) + 884 (ag-subgraph.cc:613)
13  SwiftUI                         0x00000001a1735188 GraphHost.runTransaction() + 172 (GraphHost.swift:491)
14  SwiftUI                         0x00000001a11bd184 ViewGraph.updateOutputs(at:) + 108 (ViewGraph.swift:404)
15  SwiftUI                         0x00000001a1681688 closure #1 in ViewRendererHost.render(interval:updateDisplayList:) + 1508 (ViewRendererHost.swift:188)
16  SwiftUI                         0x00000001a1677bdc ViewRendererHost.render(interval:updateDisplayList:) + 308 (ViewRendererHost.swift:0)
17  SwiftUI                         0x00000001a1813920 _UIHostingView.layoutSubviews() + 200 (UIHostingView.swift:1557)
18  SwiftUI                         0x00000001a1813954 @objc _UIHostingView.layoutSubviews() + 28 (<compiler-generated>:0)
19  UIKitCore                       0x000000019d728c20 -[UIView(CALayerDelegate) layoutSublayersOfLayer:] + 2576 (UIView.m:17543)
20  QuartzCore                      0x000000019dbaf91c -[CALayer layoutSublayers] + 308 (CALayer.mm:10147)
21  QuartzCore                      0x000000019dbafe00 CA::Layer::layout_if_needed(CA::Transaction*) + 548 (CALayer.mm:10014)
22  QuartzCore                      0x000000019dbc4a38 CA::Layer::layout_and_display_if_needed(CA::Transaction*) + 144 (CALayer.mm:2485)
23  QuartzCore                      0x000000019db06ca8 CA::Context::commit_transaction(CA::Transaction*, double, double*) + 500 (CAContextInternal.mm:2510)
24  QuartzCore                      0x000000019db32eb8 CA::Transaction::commit() + 684 (CATransactionInternal.mm:449)
25  QuartzCore                      0x000000019db341e4 CA::Transaction::observer_callback(__CFRunLoopObserver*, unsigned long, void*) + 96 (CATransactionInternal.mm:932)
26  CoreFoundation                  0x000000019a77f440 __CFRUNLOOP_IS_CALLING_OUT_TO_AN_OBSERVER_CALLBACK_FUNCTION__ + 36 (CFRunLoop.c:1799)
27  CoreFoundation                  0x000000019a779564 __CFRunLoopDoObservers + 572 (CFRunLoop.c:1912)
28  CoreFoundation                  0x000000019a779b10 __CFRunLoopRun + 1052 (CFRunLoop.c:2953)
29  CoreFoundation                  0x000000019a7791c0 CFRunLoopRunSpecific + 600 (CFRunLoop.c:3242)
30  GraphicsServices                0x00000001b1d61734 GSEventRunModal + 164 (GSEvent.c:2259)
31  UIKitCore                       0x000000019d1e77e4 -[UIApplication _run] + 1072 (UIApplication.m:3269)
32  UIKitCore                       0x000000019d1ed054 UIApplicationMain + 168 (UIApplication.m:4740)
33  SwiftUI                         0x00000001a16bd350 closure #1 in KitRendererCommon(_:) + 112 (UIKitApp.swift:34)
34  SwiftUI                         0x00000001a16bd2dc runApp<A>(_:) + 224 (<compiler-generated>:0)
35  SwiftUI                         0x00000001a11b5b4c static App.main() + 144 (App.swift:113)
36  xxx                         0x0000000102e05244 $main + 28 (<compiler-generated>:19)
37  xxx                         0x0000000102e05244 main + 40 (REST_API.swift:0)
38  libdyld.dylib                   0x000000019a435cf8 start + 4

The main landing UI :

import SwiftUI

struct w_landing: View {
    
  @State var daily_feed:CAT_BITE?
  @EnvironmentObject var env:Env
  @State var page:pages!
    
  public static var isAnimated:Bool = false
  let timer = Timer.publish(every: 1, on: .current, in: .common).autoconnect()
    
  @ViewBuilder
  var body: some View {
     
        NavigationView {
            
            ZStack {
                
                    deepLink(page: $page).onChange(of: env.open_page) { (Equatable) in
                        DispatchQueue.main.async {
                            page = Equatable
                        }
                    }.id("deep_link")
                    
                    Color.black
                    
                    //Backgroud
                    Image("background_landing")
                        .resizable()
                        .aspectRatio(contentMode: .fill)
                        .frame(width : UIScreen.main.bounds.width,
                               height : UIScreen.main.bounds.height)
                        .ignoresSafeArea(.all)
                        .onAppear(){
                            self.parseNotification()
                        }
           
                    //Grid
                    VStack {
                        
                        //DAILY FEED BUTTON
                        if ( self.daily_feed != nil ){
                            Button(action: {
                                
                                page = pages.withLabel( self.daily_feed!.type)
                                
                            } ){ catBite( i:0, dto : self.daily_feed!).environmentObject(env)  }
                        }
                        
                        //LIST GRID
                        LazyVGrid(columns: [GridItem(.flexible()),
                                            GridItem(.flexible())]
                                  ,spacing: 8){
                            
                             if Env.sharedInstance.cats.count > 0 {
                                
                                ForEach(0...Env.sharedInstance.cats.count - 1 , id : \.self) {i in
                                    
                                    if Env.sharedInstance.cats[i].type != "DAILY_FEED"  {
                                        Button(action: {
                                            
                                            page =  pages.withLabel( Env.sharedInstance.cats[i].type)
                                            
                                        }) {
                                            catBite( i:i - 1, dto : Env.sharedInstance.cats[i]  )
                                                .environmentObject(env)
                                        }
                                    }
                                  
                                }
                             }
                        }
                        
                        Spacer()
                        
                    }.padding(.top, Env.sharedInstance.hasNotch ? 80 : 50)
                     .padding([.leading,.trailing] , 20)
                     .id("the_main_list")
                
            }.id("landing")
             .navigationBarColor( .clear, textColor: .white )
             .accentColor(.white)
             .navigationBarTitleDisplayMode(.inline)
             .onAppear(){
           
                DispatchQueue.main.asyncAfter(deadline: .now() + 0.7) {
                    w_landing.isAnimated = true
                }
                
                //CheckIn
                NF_APP.checkIn {
                    self.rebuild()
                } onFail: {
                
                }
               
             }
            .onReceive(NotificationCenter.default.publisher(for: UIApplication.willEnterForegroundNotification), perform: { _ in
                parseNotification()
            })
            .onReceive(NotificationCenter.default.publisher(for: NSNotification.Name("pushRecieved")), perform: { _ in
                parseNotification()
             })
             .onReceive(timer) { time in
                env.seconds += 1
             }
            .navigationBarItems(leading:
                
                    Button(action : {
                        
                        DispatchQueue.main.async{
                            self.page = .SHARE_APP
                        }
                    } ){
                             VStack(spacing: 0){
                                 Image( "icon-invite")
                                     .resizable()
                                     .aspectRatio(contentMode: .fit)
                                     .foregroundColor(.white)
                                     .frame(width : 28, height : 28)
         
                                 Text("Invite Friends")
                                       .foregroundColor(.white)
                                       .font(Font.custom("Poppins-Light", fixedSize: 8))
                             }
                     }
                
                , trailing:
                    HStack(spacing : 20){

                        Button(action : { page = .NOTIFICATIONS} ){
                            Image(systemName: "bell.fill")
                                .resizable()
                                .aspectRatio(contentMode: .fit)
                                .foregroundColor(.white)
                                .frame(width : 25, height : 25)
                        }

                        Button(action : { page = .SETTINGS} ){
                            Image(systemName: "gearshape.fill")
                                .resizable()
                                .aspectRatio(contentMode: .fit)
                                .foregroundColor(.white)
                                .frame(width : 25, height : 25)
                        }

                    }
            ).toolbar {
                
                //LOGO mid
                ToolbarItem(placement: .principal) {
                    Image("logo-splash").resizable()
                        .aspectRatio(contentMode: .fit)
                        .frame(width : 140, height: 50)
                        
                }
            }
            
        }.navigationViewStyle(StackNavigationViewStyle())
    }
    
    
    fileprivate func parseNotification(){
        
        //Open deep link notification if exsits
        if  push_payload != nil {
            
            print("[PUSH] payload \(String(describing: push_payload))")
            
           if  let custom_data:[String:Any] = push_payload["custom_data"] as? [String:Any] {
                
                push_payload = nil
            
                let open_page:String = custom_data["open_page"] as? String ?? ""
                
                print("[PUSH] open page = \(open_page)")
            
                if open_page != "" {
                    
                    DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) {
                        page = pages.withLabel(open_page)
                    }
                
                }
           }else{
            print("[PUSH] No custom data found")
           }
            
        }else{
            print("[PUSH] Payload was nil")
        }
        
    }
    
    fileprivate func rebuild(){
        
        //Cats already loded
        if  Env.sharedInstance.cats.count > 0 {
            return
        }
        
        if let _cats:[Any] = Env.sharedInstance.checkin?.payload!["categories"] as? [Any] {
            
            Env.sharedInstance.cats = []
            for cat in _cats {
             
                guard  let cat = cat as? [String:Any] else {
                    continue
                }
                
                Env.sharedInstance.cats.append(CAT_BITE(cat))
            }
            
            if Env.sharedInstance.cats.filter({ $0.type == "DAILY_FEED"}).count > 0 {
                self.daily_feed = Env.sharedInstance.cats.filter({ $0.type == "DAILY_FEED"})[0]
            }
        }
    
    }
}

struct w_landing_Previews: PreviewProvider {
    static var previews: some View {
        w_landing()
    }
}

I've tried every solution in the Apple community and Stack Overflow, but I'm still stuck with this crash:

AttributeGraph precondition failure: invalid value type for attribute: 632448 (saw PreferenceKeys, expected ViewList).

and the only way to get the full log was to upload a version on TestFlight and send the report to myself once the app crashed On Xcode, the crash log is useless and I couldn't identify from where the crash is coming from.

like image 609
Khodour.F Avatar asked Jun 09 '21 13:06

Khodour.F


1 Answers

It's difficult to say definitively what the issue is here, but this line:

DispatchQueue.main.async{
     self.listID = UUID().uuidString //Void apple SwiftUI big in AttributeGraph cycle ( seems it worked by Jack )
}

Leads me to think you may have lurking instabilities caused by overlapping view hierarchy updates.

There's a good discussion of how arbitrarily updating your view ids can lead to issues in this week's 2021 WWDC (Demystify SwiftUI): https://developer.apple.com/wwdc21/10022

You've also got this line:

}//end of geo
.id(  self.listID )

Which forces the geo view to update itself. That coupled with the above .onAppear reset of the listID is causing your entire view hierarchy to constantly update itself (and be unstable). Here's another guide about how misplaced state changes can cause unstable behavior: https://swiftui-lab.com/state-changes/

like image 67
Eric Shieh Avatar answered Oct 18 '22 18:10

Eric Shieh