应用程序仅在 iPhone 8 iOS 14.4.1 上因内存不足而崩溃

Posted

技术标签:

【中文标题】应用程序仅在 iPhone 8 iOS 14.4.1 上因内存不足而崩溃【英文标题】:App crashes with low memory only on iPhone 8 iOS 14.4.1 【发布时间】:2021-03-21 18:24:21 【问题描述】:

我遇到了一个奇怪的错误。

我在点击标签时调用了以下方法。该方法隐藏了 UIDatePicker。这是在集合视图或表格视图中呈现的 UIViewController 中。

这是在 viewDidLoad() 中

self.StartDateLabel.addGestureRecognizer(UITapGestureRecognizer(target:self, action:#selector(self.startDateLabelTapped(_:))))

这是调用的方法。第一次点击标签会显示日期选择器,因此选择器可以工作,但再次点击会导致问题。这只发生在 iPhone 8 上。我已经在 iPhone 11、8 Plus 上进行了测试。这是一致的行为。

我还有一个这样的标签用于另一个日期选择器,同样的情况也发生在它上面。

可能是什么原因?

@objc private func startDateLabelTapped(_ sender: Any) 
        
        if self.startDatePicker.isHidden 
    
            UIView.animate(withDuration: 0.3, delay: 0, options: [.transitionFlipFromLeft]) 
    
                DispatchQueue.main.async 
    
    
                    self.startDatePicker.isHidden = false
                
             //end of UIView.animate
         else 
    
            UIView.animate(withDuration: 0.3, delay: 0, options: [.transitionFlipFromRight]) 
    
                DispatchQueue.main.async 
                    self.startDatePicker.isHidden = true //after this memory usage goes high and app crash with below stacktrace.
    
                
             //end of UIView.animate
    
        
    

Fatal Exception: NSInvalidArgumentException
0  CoreFoundation                 0x1818499d8 __exceptionPreprocess
1  libobjc.A.dylib                0x195bcfb54 objc_exception_throw
2  CoreFoundation                 0x181759bbc -[NSOrderedSet initWithSet:copyItems:]
3  UIKitCore                      0x1840e8d30 -[UIResponder doesNotRecognizeSelector:]
4  CoreFoundation                 0x18184c01c ___forwarding___
5  CoreFoundation                 0x18184df8c _CF_forwarding_prep_0
6  CoreFoundation                 0x1817ac370 __CFNOTIFICATIONCENTER_IS_CALLING_OUT_TO_AN_OBSERVER__
7  CoreFoundation                 0x1817ac330 ___CFXRegistrationPost_block_invoke
8  CoreFoundation                 0x1817ab928 _CFXRegistrationPost
9  CoreFoundation                 0x1817ab320 _CFXNotificationPost
10 Foundation                     0x1829e10a0 -[NSNotificationCenter postNotificationName:object:userInfo:]
11 Foundation                     0x182a62fa8 -[NSUbiquitousKeyValueStore _postDidChangeNotificationExternalChanges:sourceChangeCount:]
12 Foundation                     0x182be31e0 __53-[NSUbiquitousKeyValueStore _syncConcurrentlyForced:]_block_invoke_2
13 libdispatch.dylib              0x181481298 _dispatch_call_block_and_release
14 libdispatch.dylib              0x181482280 _dispatch_client_callout
15 libdispatch.dylib              0x1814645b0 _dispatch_main_queue_callback_4CF$VARIANT$armv81
16 CoreFoundation                 0x1817c95e0 __CFRUNLOOP_IS_SERVICING_THE_MAIN_DISPATCH_QUEUE__
17 CoreFoundation                 0x1817c3a88 __CFRunLoopRun
18 CoreFoundation                 0x1817c2ba0 CFRunLoopRunSpecific
19 GraphicsServices               0x19852b598 GSEventRunModal
20 UIKitCore                      0x1840b42f4 -[UIApplication _run]
21 UIKitCore                      0x1840b9874 UIApplicationMain
22 Lendable-Test                  0x10524ef38 main + 99 (AppDelegate.swift:99)
23 libdyld.dylib                  0x1814a1568 start

在 isHidden 之后使用 print 语句检查了该方法是否被调用。在它之后没有执行特定于应用程序的代码,并且内存跳转执行一些内部代码。由于内存原因,我无法捕捉到使用断点作为应用程序崩溃的情况。

来自 Instruments 的三张截图。我不知道如何分析这些数据

内存泄漏

当我在内存快用完之前暂停时,我得到了这个堆栈跟踪。奇怪的是,我的应用程序在 iPhone 8 模拟器上运行良好,但仅在设备上失败!我保存了添加的堆栈跟踪。我不知道为什么当我在另一个视图上隐藏控件时会执行与集合视图相关的代码。

#0  0x0000000195bcb498 in objc_msgSend ()
#1  0x00000001837a5d3c in __68-[NSCollectionLayoutSize _effectiveSizeForContainer:ignoringInsets:]_block_invoke ()
#2  0x00000001837a5c44 in -[NSCollectionLayoutSize _effectiveSizeForContainer:ignoringInsets:] ()
#3  0x00000001837d07a4 in -[_UICollectionLayoutItemSolver layoutFrame] ()
#4  0x00000001837d6ff0 in -[_UICollectionSolutionGroupArrangementItem initWithSolution:] ()
#5  0x00000001837d1764 in -[_UICollectionLayoutItemSolver _solveGroup] ()
#6  0x00000001837d0c64 in -[_UICollectionLayoutItemSolver _solveForContainer:layoutAxis:traitCollection:maxFrameCount:layoutRTL:preferredSizes:solutionRecursionDepth:] ()
#7  0x00000001837d1648 in -[_UICollectionLayoutItemSolver _solveGroup] ()
#8  0x00000001837d0c64 in -[_UICollectionLayoutItemSolver _solveForContainer:layoutAxis:traitCollection:maxFrameCount:layoutRTL:preferredSizes:solutionRecursionDepth:] ()
#9  0x00000001837cf92c in -[_UICollectionLayoutItemSolver solveForContainer:layoutAxis:traitCollection:maxFrameCount:layoutRTL:preferredSizes:] ()
#10 0x00000001837cf89c in -[_UICollectionLayoutItemSolver solveForContainer:layoutAxis:traitCollection:maxFrameCount:layoutRTL:] ()
#11 0x00000001837df388 in -[_UICollectionLayoutSectionFixedSolver _solve] ()
#12 0x00000001837bb1a0 in -[_UICollectionCompositionalLayoutSolver _solveWithSectionLayouts:preferredSizesDict:dataSourceSnapshot:update:] ()
#13 0x00000001837bac24 in -[_UICollectionCompositionalLayoutSolver _solve] ()
#14 0x00000001837b5944 in -[_UICollectionCompositionalLayoutSolver resolveForContainerChange:] ()
#15 0x00000001837acf68 in -[UICollectionViewCompositionalLayout _boundsChangeResolve] ()
#16 0x00000001837aaaec in -[UICollectionViewCompositionalLayout invalidateLayoutWithContext:] ()
#17 0x0000000183832f00 in -[UICollectionView _invalidateLayoutForUpdatedLayoutMarginsIfNeeded] ()
#18 0x0000000183832dc8 in -[UICollectionView layoutMarginsDidChange] ()
#19 0x0000000184592374 in -[UIView _layoutMarginsDidChangeFromOldMargins:] ()
#20 0x0000000184592acc in -[UIView _updateInferredLayoutMarginsFromSuperview:] ()
#21 0x00000001845a50c4 in -[UIView(Geometry) setBounds:] ()
#22 0x0000000184533548 in -[UIScrollView setBounds:] ()
#23 0x0000000183832474 in -[UICollectionView setBounds:] ()
#24 0x00000001845a43b0 in -[UIView(Geometry) _applyISEngineLayoutValuesToBoundsOnly:] ()
#25 0x00000001845a4790 in -[UIView(Geometry) _resizeWithOldSuperviewSize:] ()
#26 0x00000001844c8184 in -[UIScrollView(_UIOldConstraintBasedLayoutSupport) _resizeWithOldSuperviewSize:] ()
#27 0x00000001845a3c8c in __46-[UIView(Geometry) resizeSubviewsWithOldSize:]_block_invoke ()
#28 0x00000001817cd1d0 in __NSARRAY_IS_CALLING_OUT_TO_A_BLOCK__ ()
#29 0x0000000181731478 in -[__NSArrayM enumerateObjectsWithOptions:usingBlock:] ()
#30 0x00000001845a3be8 in -[UIView(Geometry) resizeSubviewsWithOldSize:] ()
#31 0x00000001844d619c in -[UIView(AdditionalLayoutSupport) _is_layout] ()
#32 0x00000001845ab8ac in -[UIView _updateConstraintsAsNecessaryAndApplyLayoutFromEngine] ()
#33 0x0000000183cff4e8 in -[_UIDatePickerCalendarDateView layoutSubviews] ()
#34 0x00000001845be398 in -[UIView(CALayerDelegate) layoutSublayersOfLayer:] ()
#35 0x0000000184ac3df4 in -[CALayer layoutSublayers] ()
#36 0x0000000184aca398 in CA::Layer::layout_if_needed(CA::Transaction*) ()
#37 0x0000000184ad56e8 in CA::Layer::layout_and_display_if_needed(CA::Transaction*) ()
#38 0x0000000184a20d7c in CA::Context::commit_transaction(CA::Transaction*, double, double*) ()
#39 0x0000000184a4af40 in CA::Transaction::commit() ()
#40 0x0000000184a4c1f0 in CA::Transaction::observer_callback(__CFRunLoopObserver*, unsigned long, void*) ()
#41 0x00000001817c887c in __CFRUNLOOP_IS_CALLING_OUT_TO_AN_OBSERVER_CALLBACK_FUNCTION__ ()
#42 0x00000001817c2f50 in __CFRunLoopDoObservers ()
#43 0x00000001817c3498 in __CFRunLoopRun ()
#44 0x00000001817c2ba0 in CFRunLoopRunSpecific ()
#45 0x000000019852b598 in GSEventRunModal ()
#46 0x00000001840b42f4 in -[UIApplication _run] ()
#47 0x00000001840b9874 in UIApplicationMain ()
#48 0x000000010325aef0 in main at /Users/ashishn/Documents/Developer/XCode Projects/YOVL-Xcode/Source/AppDelegate.swift:99
#49 0x00000001814a1568 in start ()

【问题讨论】:

一般sender应该设置为UITapGestureRecognizer,而不是Any,即func startDateLabelTapped(_ sender: UITapGestureRecognizer)。我不知道它是否会导致这样的崩溃 我没有在方法中使用 sender 对象,所以它可能不会影响。我在 isHidden 之后使用 print 语句检查了该方法是否被调用。在它之后没有执行应用程序特定的代码,并且内存跳转执行一些内部代码。由于内存,我无法捕捉到使用断点也作为应用程序崩溃。添加了来自 Instruments 的两个屏幕截图。 【参考方案1】:

您正在为一个隐藏视图设置动画,并且还在动画块内插入一个异步调度来改变隐藏状态......这对我来说似乎是错误的。

试试这段代码,它会为alpha 属性设置动画,并在隐藏时使用完成块打开隐藏属性。

@objc private func startDateLabelTapped(_ sender: Any) 

    if self.startDatePicker.isHidden 
    
       // un-hide it
       self.startDatePicker.isHidden = false
       UIView.animate(withDuration: 0.3, delay: 0, options: [.transitionFlipFromLeft]) 
       
            // animate alpha to make it visible
            self.startDatePicker.alpha = 1.0
        completion:  (success: Bool) in
       
    
    else
    
        UIView.animate(withDuration: 0.3, delay: 0, options: [.transitionFlipFromLeft]) 
        
            // animate alpha to make it invisible
            self.startDatePicker.alpha = 0
         completion:  (success: Bool) in
            // then hide it once animation is complete
            self.startDatePicker.isHidden = true
        
    

请注意,这将 alpha 动画与翻转过渡结合在一起......换句话说,它将在翻转期间淡入/淡出。如果您希望这些是离散的,翻转然后淡入/淡出,您可以通过链接动画来实现这一点。使用 UIView.animation completion 块开始第二个动画。

【讨论】:

这没有帮助。我创建了一个模拟类似场景的示例项目,即带有集合视图的 VC,打开带有隐藏/显示的 VC。奇怪的是,我的应用程序在 iPhone 8 模拟器上运行良好,但仅在设备上失败!我保存了添加的堆栈跟踪。我不知道为什么当我在另一个视图上隐藏控件时会执行与集合视图相关的代码。【参考方案2】:

从this 答案中得到提示,我将 UIDatePicker 嵌入到 UIView 中,它解决了这个问题。该线程上报告的问题与我面临的问题不同,因此希望此解决方案有助于功能上的类似问题。

我将方法更改为如下以添加隐藏和显示嵌入视图。

@objc private func startDateSelectionLabelTapped(_ sender: Any) 
        
        if self.startDatePicker.isHidden 

            // un-hide it
            self.startDatePicker.isHidden = false
            self.startDatePickerembeddingView.isHidden = false

            UIView.animate(withDuration: 0.5, delay: 0, options: [.transitionFlipFromTop]) 

                // animate alpha to make it visible
                self.startDatePicker.alpha = 1.0
                
             //end of UIView.animate
            
         else 

            UIView.animate(withDuration: 0.5, delay: 0, options: [.transitionFlipFromBottom]) 

                // animate alpha to make it invisible
                self.startDatePicker.alpha = 0
                self.startDatePicker.isHidden = true
                self.startDatePickerembeddingView.isHidden = true

             //end of UIView.animate

        
    

【讨论】:

以上是关于应用程序仅在 iPhone 8 iOS 14.4.1 上因内存不足而崩溃的主要内容,如果未能解决你的问题,请参考以下文章

FBSDKGraphRequest FBSDKGraphRequestConnection 仅在 iOS 9 中返回错误

如何仅在中国启动我的 iOS iPhone 应用程序?

iOS 9 Safari webkit 仅在 iPad 上崩溃(iPhone 工作正常)

iOS 8 和 Monogame 的方向错误?

仅在 iPhone 上测试通用应用程序

iOS 14.4.1 Rootless 越狱?HomePod 已停售