Xcode16 - iOS18 - Crash

升级到 iOS18 之后项目中遇到了几个Crash 的问题,在此记录一下,也希望能帮助到大家。

  • 问题1:Set maskView,是由 QMUIToastView中的maskView 导致的,断点在这个didInitialize 方法中
- (void)didInitialize {
    
    self.tintColor = UIColorWhite;
    self.toastPosition = QMUIToastViewPositionCenter;
    // 顺序不能乱,先添加backgroundView再添加contentView
    self.backgroundView = [self defaultBackgrondView];
    self.contentView = [self defaultContentView];
    self.opaque = NO;
    self.alpha = 0.0;
    self.backgroundColor = UIColorClear;
    self.layer.allowsGroupOpacity = NO;
    _maskView = [[UIView alloc] init];
    self.maskView.backgroundColor = UIColorClear;
    [self addSubview:self.maskView];
    
    [self registerNotifications];
}

控制台报错信息:

Thread 1: "Set `maskView` (<UIView: 0x130d21980; frame = (0 0; 0 0); 
backgroundColor = UIExtendedSRGBColorSpace 1 1 1 0, 
RGBA(255, 255, 255, 0.00), #00ffffff; layer = <CALayer: 0x143e9ee80>>) to `nil` before adding it as a subview of 
<QMUITips: 0x11a9ab980;frame = (0 0; 375 812); alpha = 0; opaque = NO; tintColor = UIExtendedSRGBColorSpace 1 1 1 1, 
RGBA(255, 255, 255, 1.00), #ffffffff; backgroundColor = UIExtendedSRGBColorSpace 1 1 1 0,
 RGBA(255, 255, 255, 0.00), #00ffffff; layer = <CALayer: 0x144921b80>>"

解决办法:将.h文件和.m文件中的maskView修改成其它命名

@property(nonatomic, strong, readonly) UIView *qmui_maskView;
_qmui_maskView = [[UIView alloc] init];
self.maskView.backgroundColor = UIColorClear;
[self addSubview:self.maskView];
  • 问题2:Crash using NSMutableAttributedString with an HMTL document inside a collection view

我出错的代码

- (NSMutableAttributedString *)attributeStrWithSize:(CGFloat)size {   
    NSString *htmlString = [NSString stringWithFormat:@"<html><body> %@ <font size=\"%f\"> </body></html>",self,size];
    NSMutableAttributedString *attibuteStr = [[NSMutableAttributedString alloc] initWithData:
    [htmlString dataUsingEncoding:NSUnicodeStringEncoding] options:@{NSDocumentTypeDocumentAttribute: 
    NSHTMLTextDocumentType} documentAttributes:nil error:nil];
    return attibuteStr;
}

解决办法:将它加入到主线程即可

- (NSMutableAttributedString *)attributeStrWithSize:(CGFloat)size {   
    NSMutableAttributedString *attibuteStr = [[NSMutableAttributedString alloc] initWithString:self];
    dispatch_async(dispatch_get_main_queue(), ^{
        NSString *htmlString = [NSString stringWithFormat:@"<html><body> %@ <font size=\"%f\"> </body></html>",self,size];
        NSMutableAttributedString *attibuteStr = [[NSMutableAttributedString alloc] initWithData:
        [htmlString dataUsingEncoding:NSUnicodeStringEncoding] options:@{NSDocumentTypeDocumentAttribute: 
        NSHTMLTextDocumentType} documentAttributes:nil error:nil];
        attibuteStr = attibuteStr;
    });
    return attibuteStr;
}
  • 问题3:这个是很多人遇到最多的问题,大概的意思就是执行了多次dequeueReusableCell,我这里的报错信息如下:
UICollectionView _updateVisibleCellsNow

Exception   NSException *   "Expected dequeued view to be returned to the collection view in preparation for display. 
When the collection view's data source is asked to provide a view for a given index path, ensure that a single view 
is dequeued and returned to the collection view. Avoid dequeuing views without a request from the collection view. For retrieving an existing view in the collection view, 
use -[UICollectionView cellForItemAtIndexPath:] or -[UICollectionView supplementaryViewForElementKind:atIndexPath:]. 
Dequeued view: <UICollectionReusableView: 0x116113200; frame = (0 301.333; 393 50); layer = <CALayer: 0x1161852c0>>; 
Collection view: <UICollectionView: 0x109ec4000; frame = (0 0; 393 754.333); clipsToBounds = YES; gestureRecognizers = <NSArray: 0x10cb33930>; 
backgroundColor = <UIDynamicProviderColor: 0x10cacbe20; provider = <__NSMallocBlock__: 0x10c833fc0>>; layer = <CALayer: 0x10cacbcc0>; 
contentOffset: {0, 0}; contentSize: {393, 1029.105}; adjustedContentInset: {0, 0, 83, 0}>, contentInset = {0, 0, 0, 0; layout: <YKCollect"...   0x00000001161777b0

但是断点断在了MJRefresh的UIScrollView+MJExtension里面

- (void)setMj_insetT:(CGFloat)mj_insetT
{
    UIEdgeInsets inset = self.contentInset;
    inset.top = mj_insetT;
#ifdef __IPHONE_11_0
    if (respondsToAdjustedContentInset_) {
        inset.top -= (self.adjustedContentInset.top - self.contentInset.top);
    }
#endif
    self.contentInset = inset;
}

就很奇怪,摸不着头脑,上GitHub找MJRefresh的issue也没有类似的,又各种百度、google,终于在https://developer.apple.com/forums/上面找到了解决方案。每个人的具体需要改的代码位置不一样,有可能在- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath中,也有可能在- (UICollectionReusableView *)collectionView:(UICollectionView *)collectionView viewForSupplementaryElementOfKind:(NSString *)kind atIndexPath:(NSIndexPath *)indexPath中,所以你需要注意的是不要多次加载dequeueReusableCell。

解决方案如下:
改动前

- (UICollectionReusableView *)collectionView:(UICollectionView *)collectionView viewForSupplementaryElementOfKind:(NSString *)kind atIndexPath:(NSIndexPath *)indexPath {
    if ([kind isEqualToString:UICollectionElementKindSectionHeader]) {
        //这个地方就是多次调用了dequeueReusableSupplementaryViewOfKind
        UICollectionReusableView *view = [self.collectionView dequeueReusableSupplementaryViewOfKind:UICollectionElementKindSectionHeader withReuseIdentifier:collectionNilSectionHeader forIndexPath:indexPath];
        WS(weakSelf);
        if (self.tagbqArray.count != 0) {
            YKSectionHeaderCollectionReusableView *sliderView = [self.collectionView dequeueReusableSupplementaryViewOfKind:UICollectionElementKindSectionHeader withReuseIdentifier:collectionSliderSectionHeader forIndexPath:indexPath];
            static NSString *collectionNilSectionFooter = @"collectionNilSectionFooter";
            [weakSelf updateShopData:model];
            };
            return sliderView;
        } 
        return view;   
    }

改动后

- (UICollectionReusableView *)collectionView:(UICollectionView *)collectionView viewForSupplementaryElementOfKind:(NSString *)kind atIndexPath:(NSIndexPath *)indexPath {
    if ([kind isEqualToString:UICollectionElementKindSectionHeader]) {
        WS(weakSelf);
        if (self.tagbqArray.count != 0) {
            YKSectionHeaderCollectionReusableView *sliderView = [self.collectionView dequeueReusableSupplementaryViewOfKind:UICollectionElementKindSectionHeader withReuseIdentifier:collectionSliderSectionHeader forIndexPath:indexPath];
            static NSString *collectionNilSectionFooter = @"collectionNilSectionFooter";
            [weakSelf updateShopData:model];
            };
            return sliderView;
        } else {
            UICollectionReusableView *view = [self.collectionView dequeueReusableSupplementaryViewOfKind:UICollectionElementKindSectionHeader withReuseIdentifier:collectionNilSectionHeader forIndexPath:indexPath];
            return view;
        } 
    }

如何把 UITabBar 移到底部?UITabBarController 的 sideBar
iPadOS 18.1 + Xcode 16.1 仅仅设置self.mode = UITabBarControllerModeTabBar不起作用

// 在UITabBarController子类里

#if __IPHONE_OS_VERSION_MAX_ALLOWED >= 180000
    if (@available(iOS 18.0, *)) {
        if (UIDevice.currentDevice.userInterfaceIdiom == UIUserInterfaceIdiomPad) {
            self.mode = UITabBarControllerModeTabBar;
            self.traitOverrides.horizontalSizeClass = UIUserInterfaceSizeClassCompact;
            [self.view addSubview:self.tabBar];
            NSString *tabContainerClassName = [NSString stringWithFormat:@"%@%@%@", @"_UITab", @"Container", @"View"];
            for (UIView *subview in self.view.subviews) {
                if ([NSStringFromClass(subview.class) isEqualToString:tabContainerClassName]) {
                    [subview setHidden:YES];
                }
            }
        }
    }
#endif

如果你也遇到了类似问题,但还是没有解决好,可以在下面回复我,我来帮你一起解决。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容