uni-app UNIAPPXIOS UTS标准组件 在改组件快速切换v-if时 native-view @init 只要使用 e.detail.element 就会闪退崩溃

uni-app UNIAPPXIOS UTS标准组件 在改组件快速切换v-if时 native-view @init 只要使用 e.detail.element 就会闪退崩溃

开发环境 版本号 项目创建方式
Mac 14.7.8 (23H730) HBuilderX

操作步骤:

<template>  
    <view class="xb-image-x" :class="new Map<string, boolean>([['unScaleToFill',mode !== 'scaleToFill']])">  
        <image class="xb-image-x-image" :src="src" :mode="mode" :lazy-load="lazyLoad" :fade-show="fadeShow" :webp="webp"  
            :show-menu-by-longpress="showMenuByLongpress" :draggable="draggable" @error="onError" @load="onLoad" v-if="src">  
        </image>  
        <template v-if="showLoading">  
            <view class="loading" v-if="status === 'loading'">  
                <image class="loading-image" src="/uni_modules/xb-image-x/static/xbImageXplaceholder.png" mode="aspectFill">  
                </image>  
                <view class="animation">  
                    <view style="width: 100px; height: 50px; margin: 0 auto;">  
                        <xb-n-lottie :json="lottieLoadingJson"></xb-n-lottie>  
                    </view>  
                </view>  
            </view>  
        </template>  
    </view>  
</template>  
<script setup>  
import lottieLoadingJson from '@/static/lottie/Loading.json'  

const emit = defineEmits(['error', 'load'])  

const props = defineProps({  
    bindclass: {  
        type: String,  
        default: '',  
    },  
    src: {  
        type: String,  
        default: '',  
    },  
    mode: {  
        type: String,  
        default: 'scaleToFill',  
    },  
    lazyLoad: {  
        type: Boolean,  
        default: false,  
    },  
    fadeShow: {  
        type: Boolean,  
        default: false,  
    },  
    webp: {  
        type: Boolean,  
        default: true,  
    },  
    showMenuByLongpress: {  
        type: Boolean,  
        default: false,  
    },  
    draggable: {  
        type: Boolean,  
        default: false,  
    },  
    showLoading: {  
        type: Boolean,  
        default: true,  
    },  
})  

const status = ref('loading')  

// 加载失败  
const onError = (event: UniImageErrorEvent) => {  
    status.value = 'error'  
    emit('error', event)  
}  

// 加载成功  
const onLoad = (event: UniImageLoadEvent) => {  
    status.value = 'success'  
    emit('load', event)  
}  

onMounted(() => {  
    removeHidden.value = true;  
})  
</script>

xb-n-lottie.uvue

<template>  
    <!-- <view class="native-view-box"> -->  
    <native-view class="native-view" [@init](/user/init)="onviewinit"></native-view>  
    <!-- </view> -->  
</template>  
<script setup lang="uts">  
// #ifdef APP-IOS  
import { NativeView } from "@/uni_modules/xb-lottie";  
// #endif  
let nativeView : NativeView | null = null  

//声明属性  
const props = defineProps<{  
    json : UTSJSONObject  
}>()  

//声明事件  
const emit = defineEmits<{  
    (e : "init", event : UniNativeViewInitEvent) : void  
}>()  

//native-view初始化时触发此方法  
function onviewinit(e : UniNativeViewInitEvent) {  
    console.log(e.detail.element)  
}  

defineExpose({  
})  

function onUnmounted() {  
    nativeView?.destroy()  
}  

onBeforeUnmount(() => {  
    onUnmounted()  
})  
</script>

预期结果:

  • 不出现闪退

实际结果:

  • 闪退

bug描述:

比如在以上代码逻辑中,某些图片已经加载过一次有缓存了,会快速触发status.value = 'success'导致<xb-n-lottie  />组件消失 onviewinit  触发之后 哪怕是console.log(e.detail.element) 也会引起崩溃闪退,查看堆站日志发现
Thread 0 Crashed:
UniNativeViewComponent.sendInitEvent() + 636
→ layoutDidFinish()
→ _layoutDidFinish
→ UniJsBridge.registerPageFunction()
→ handleDisplayLink()

更多关于uni-app UNIAPPXIOS UTS标准组件 在改组件快速切换v-if时 native-view @init 只要使用 e.detail.element 就会闪退崩溃的实战教程也可以访问 https://www.itying.com/category-93-b0.html

1 回复

更多关于uni-app UNIAPPXIOS UTS标准组件 在改组件快速切换v-if时 native-view @init 只要使用 e.detail.element 就会闪退崩溃的实战教程也可以访问 https://www.itying.com/category-93-b0.html


这是一个典型的iOS原生组件生命周期管理问题。当xb-n-lottie组件因v-if快速切换而被销毁时,native-view@init事件仍在执行,此时访问e.detail.element会导致访问已释放的内存对象而闪退。

问题分析:

  1. 图片缓存导致status.value快速变为success
  2. xb-n-lottie组件被立即销毁
  3. native-view的初始化回调仍在执行队列中
  4. 访问已销毁组件的element属性引发野指针访问

解决方案:

xb-n-lottie.uvue中添加销毁标志位:

let isDestroyed = false

function onviewinit(e : UniNativeViewInitEvent) {
    if (isDestroyed) return
    console.log(e.detail.element)
}

function onUnmounted() {
    isDestroyed = true
    nativeView?.destroy()
}

根本原因: iOS原生组件在UTS中的销毁是异步的,而事件回调可能仍在主线程队列中等待执行。当组件因条件渲染快速移除时,需要手动管理回调的安全执行。

建议优化: 在父组件中对xb-n-lottie的使用添加防抖处理,避免因状态频繁切换导致的组件快速挂载/卸载:

const showLottie = debounceRef(status.value === 'loading', 100)
回到顶部