[iOS]SDK版本0.10.3版本WXComponentManage.m中rootNodeGetChild函数引发崩溃

1.某些页面进行渲染的时候会引起iOS程序崩溃,但是并不是每一次都会崩溃,比如 a 页面 jump b页面 然后 b back a 然后 一直重复,某次会引起崩溃,安卓未发现
2.页面代码
<template>

<div append="tree">
    <!--导航栏-->
    <div class="nav-bar">
        <div class="nav-left" @click="onBack">
            <image class="nav-ico" src="images/nav_icon_return.png"></image>
        </div>
        <div class="nav-center">
            <text class="nav-tit" lines="1">{{trainingTitle}}</text>
        </div>
        <div class="nav-right" @click="showClassDialog()">
            <text class="nav-right-text">切班</text>
        </div>
    </div>
    <!--/导航栏-->
    <!--页面内容-->
    <div>
        <div class="class-detail-info">
            <div class="detail-info-height">
                <text class="detail-info-text" v-if="isClassDetail">[{{classDetail.trainingYear}}][{{classDetail.grade}}][{{classDetail.learningCategory}}]</text>
            </div>
            <div class="detail-chart" >
                <web ref="knob" class="webview-class" @pagestart="loading" @pagefinish="finish" @error="error" :src="myUrl" v-if="isClassDetail"></web>
            </div>
            <div class="info-btn-box">
                <div class="info-btn-items bor-r" @click="ShowQuireDailog()">
                    <text class="info-btn-text">考核要求</text>
                </div>
                <div class="info-btn-items" @click="ShowNoQuireDailog()">
                    <text class="info-btn-text" :class="[noRequireShowGray()]">未通过考核?</text>
                </div>
            </div>
        </div>
    </div>
    <!--/页面内容-->
    <Tabbar :trainingClassId="getTrainingClassId()"></Tabbar>
    <router-view></router-view>
    <div class="tab-bar">
        <div class="tab-items-1" @click="jumpSelectCourse()">
            <image class="tab-icon" src="images/icon_course_select.png"></image>
            <text class="tab-name-1" :class="[selectSourseText()]">去选课</text>
        </div>
    </div>
    <!--班级切换对话框-->
    <ClassListDialog ref="classListDialog" @closeTip="setTrainingTitle()"></ClassListDialog>
    <!--考核要求对话框-->
    <QuireDialog ref="quireDialog"></QuireDialog>
    <!--未通过考核对话框-->
    <NoquireDialog ref="noQuireDialog"></NoquireDialog>
    <!--&lt;!&ndash;未通过考核对话框&#45;&#45;&#45;&#45;重学班级&ndash;&gt;-->
    <NoRequireReLearningDialog ref="noRequireReLearningDialog" @closeTip="showRelearningClass"></NoRequireReLearningDialog>
    <!--&lt;!&ndash;重学班级对话框&ndash;&gt;-->
    <ReLearningClassDialog ref="twoReLearningClassDialog" :trainingClassId="trainingClassId"></ReLearningClassDialog>
    <!--&lt;!&ndash;加载中&ndash;&gt;-->
    <!--<MyLoading :isShow="isLoading()"></MyLoading>-->
</div>

</template>

<style src="../../styles/public.css" scoped></style>
<style src="../../styles/ClassDetail.css" scoped></style>
<style src="../../styles/dialog.css" scoped></style>

<script>

import * as types from "../../store/types";
import Tabbar from "../../components/classDetail-tabbar.vue"
import MyLoading from "../../components/Loading.vue"
import NoquireDialog from './ClassDetail_Noquire_Dialog.vue'
import QuireDialog from './ClassDetail_Quire_Dialog.vue'
import ClassListDialog from './ClassDetail_ClassLIst_Dialog.vue'
import NoRequireReLearningDialog from './ClassDetail_reLearning_Class_Dialog.vue'
import ReLearningClassDialog  from './ClassDetail_reLearning_Class_Confirm_Dialog.vue'
const webview = weex.requireModule ( 'webview' );
export default{
    components: {Tabbar,MyLoading,NoquireDialog,QuireDialog,ClassListDialog,NoRequireReLearningDialog,ReLearningClassDialog},
    computed: {
        myUrl() {
            var params=this.$store.state.trainClassDetailModule.params;
            var url=this.url + '?params=' + encodeURI(JSON.stringify(params));
            console.log('url+params>>>>>'+JSON.stringify(params));
            return url;
        },
        //班级详情数据
        classDetail(){
            var value=this.$store.state.trainClassDetailModule.trainClassDetail;
            if(value==null||value==undefined){
                value=''
            }else {
                return value;
            }
        },
        isClassDetail(){
            var value=this.$store.state.trainClassDetailModule.trainClassDetail.trainingYear
            if(value==null||value==undefined){
                return false;
            }else {
                return true;
            }
        },
        getTrainingYear(){
            var value=this.$store.state.trainClassDetailModule.trainClassDetail;
            if(value==null||value==undefined){
                value=' '
            }else {
                var trainingYear=value.trainingYear
                if(trainingYear!=null&&trainingYear!=undefined&&trainingYear!=''){
                    value='['+trainingYear+']'
                }
            }
            return value;
        },
        getGrade(){
            var value=this.$store.state.trainClassDetailModule.trainClassDetail;
            if(value==null||value==undefined){
                value=' '
            }else {
                var grade=value.grade
                if(grade!=null&&grade!=undefined&&grade!=''){
                    value='['+grade+']'
                }
            }
            return value;
        },
        getLearningCategory(){
            var value=this.$store.state.trainClassDetailModule.trainClassDetail;
            if(value==null||value==undefined){
                value=' '
            }else {
                var learningCategory=value.learningCategory
                if(learningCategory!=null&&learningCategory!=undefined&&learningCategory!=''){
                    value='['+learningCategory+']'
                }
            }
            return value;
        }
    },
    props: {
    },
    data () {
        return {
            trainingClassId: '',
            params: {
                mode:null,//1分数  2 文字
                percent: 0,//百分比
                text:null,//分数展示内容 如果mode=2 则展示这个内容
                score:null,//得分  如果mode=1 则展示分数
                isPassed:true,//是否通过 用来展示通过图标
                passText:null//是否通过文本内容 必须提供默认为未知
            },
            url: 'http://172.17.0.137:5555/knob.html',
            noQuireClick:false,
            trainingTitle:'',
            timer:{},
        }
    },
    watch: {
        myUrl: function () {
            //webview.reload(this.$refs.knob);
        }
    },
    methods: {
        onBack(){
            this.back();
            console.log("back");
        },
        loading: function () {},
        finish: function () {},
        error: function () {},
        /**
         * 显示班级对话框
         */
        showClassDialog(){
            this.$store.dispatch(types.CD_REQUEST_CLASS_LIST).then((data)=>{
                console.log('班级列表>>>>>>' + JSON.stringify(data))
                if(data.head.code !== types.NETWORK_RESULT_SUCCESS){
                    this.toast(data.head.message);
                }else{
                    this.$refs.classListDialog.show();
                 }
            }).catch((data)=>{
                this.toast(data.head.message);
             })
        },
        /**
         * 显示未通过考核对话框
         */
        ShowNoQuireDailog(){
            if(this.noQuireClick){
                if(this.$store.state.trainClassDetailModule.trainClassDetail.remainderNum>0){
                    //显示去课程练习对话框
                    this.$refs.noQuireDialog.show ();
                }else{
                    //显示去整班重学
                    this.$refs.noRequireReLearningDialog.show();
                }

            }
        },
        /**
         * 显示考核对话框
         */
        ShowQuireDailog(){
            this.$refs.quireDialog.show ();
        },
        isLoading(){
            return this.$store.state.trainClassDetailModule.loadingState.count > 0;
        },
        //选课
        jumpSelectCourse(){
            if(this.$store.state.trainClassDetailModule.trainClassDetail.electiveCondition){
                this.toast('已达选课要求,无需继续选课')
                return
            }
            this.$store.commit(types.CD_SELECT_SOURSE_LOADING_DATA,false);
            this.$router.push({name:'selectCourse',params:{trainingClassId:this.$store.state.trainClassDetailModule.trainClassId}});
            this.$store.commit(types.CD_SELECT_SOURSE_TAB_INDEX,0);
            this.$store.commit(types.CLASS_DETAIL_SET_SELTED_COURSE_SELECTED_HOURS,0);
        },
        /**
         * 网络请求:班级详情
         */
        requireClassDetail(){
            this.$store.dispatch(types.DETAIL_REQUEST_CLASS_DETAIL,this.trainingClassId).then((data)=>{
                console.log('班级详情>>>>>>' + JSON.stringify(data))
                if(data.head.code !== types.NETWORK_RESULT_SUCCESS){
                    this.toast(data.head.message);
                }else{
                    this.classTrainResult();
                    this. setTrainingTitle();
                }
            }).catch((data)=>{
                this.toast(data.head.message);
            });
        },
        /**
         * 网络请求:班级课程列表
         */
        requireCDCourseList(){
            this.$store.dispatch(types.DETAIL_REQUEST_COURSE_LIST,this.trainingClassId).then((data)=>{
                console.log('班级课程列表>>>>>>' + JSON.stringify(data))
                if(data.head.code !== types.NETWORK_RESULT_SUCCESS){
                    this.toast(data.head.message);
                }
            }).catch((data)=>{
                this.toast(data.head.message);
            });
        },
        /**
         * 网络请求:班级课程信息
         */
        requireCDCourseInformation(){
            this.$store.dispatch(types.CLASS_DETAIL_REQUEST_COURSE_INFORMATION,this.trainingClassId).then((data)=>{
                console.log('班级课程信息>>>>>'+JSON.stringify(data));
                if(data.head.code !== types.NETWORK_RESULT_SUCCESS){
                    this.toast(data.head.message);
                }
            }).catch((data)=>{
                this.toast(data.head.message);
            });
        },
        /**
         * 网络请求:班级考试列表
         */
        requireCDExamList(){
            this.$store.dispatch(types.DETAIL_REQUEST_EXAM_LIST,this.trainingClassId).then((data)=>{
                console.log('班级考试列表>>>>>>' + JSON.stringify(data))
                if(data.head.code !== types.NETWORK_RESULT_SUCCESS){
                    this.toast(data.head.message);
                }
            }).catch((data)=>{
                this.toast(data.head.message);
            });
        },
        isLoading(){
            return this.$store.state.trainClassDetailModule.loadingState.count > 0;
        },
        getTrainingClassId(){
            return this.trainingClassId;
        },
        /**
         *培训结果判断
         */
        classTrainResult(){
            var iSResult=this.$store.state.trainClassDetailModule.trainClassDetail.electiveCondition;
            if(!iSResult){
                this.params.text='学习中';
                this.params.mode=2;
                this.params.isPassed=false;
                this.params.percent=0;
            }else {
                this.params.mode=1;
                this.params.score=this.$store.state.trainClassDetailModule.trainClassDetail.score;
                this.params.percent=this.$store.state.trainClassDetailModule.trainClassDetail.score;
                if(this.$store.state.trainClassDetailModule.trainClassDetail.assessResult==0){
                    this.params.passText='未通过'
                    this.params.isPassed=false;
                }else {
                    this.params.passText='通过'
                    this.params.isPassed=true;
                }
            }
            this.$store.dispatch(types.DETAIL_SET_CLASS_DETAIL_PARAMS,this.params);
        },
        noRequireShowGray(){
            if(this.$store.state.trainClassDetailModule.trainClassDetail.completePercent==100){
                if(this.$store.state.trainClassDetailModule.trainClassDetail.assessResult==0){
                    this.noQuireClick=true;
                    return 'info-btn-text';
                }else {
                    this.noQuireClick=false;
                    return 'info-btn-gray';
                }
            }else {
                this.noQuireClick=false;
                return 'info-btn-gray';
            }
            this.noQuireClick=true;
            return 'info-btn-text'
        },
        showRelearningClass(){
            this.$refs.twoReLearningClassDialog.show();
        },
        /**
         * 选课的文字
         */
        selectSourseText(){
            if(this.$store.state.trainClassDetailModule.trainClassDetail.electiveCondition){
                return 'tab-name-gray-1'
            }else {
                return 'tab-name-1'
            }
        },
        setTrainingTitle(){
            this.trainingTitle=this.classDetail.trainingClassName;
            if(this.trainingTitle.length>12){
                this.scrollTitleAction();
            }else {
                clearInterval(this.timer);
            }
        },
        scrollTitleAction(){
            clearInterval(this.timer);
            this.timer=setInterval(()=>{
                var tempStr = this.trainingTitle;
                tempStr = tempStr.substr(1, tempStr.length - 1) + tempStr.substr(0, 1);
                this.trainingTitle = tempStr;
            },500)
        }
    },
    beforeCreate: function () {

    },
    created:function () {
        this.trainingClassId=this.$store.state.trainClassDetailModule.trainClassId;
        //清除数据
        if(this.$route.params.trainingClassId!=this.$store.state.trainClassDetailModule.trainClassDetail.trainingClassId){
            var data= {}
            this.$store.commit(types.DETAIL_SET_CLASS_DETAIL,data);
            this.$store.commit(types.DETAIL_SET_COURSE_LIST,data);
            this.$store.commit(types.CLASS_DETAIL_SET_COURSE_INFORMATION,data)
            this.$store.commit(types.DETAIL_SET_EXAM_LIST,data)
            this.$store.commit(types.CLASS_DETAIL_SET_EXAM_INFORMATINO,'')
            this.$store.commit(types.CLASS_DETAIL_SET_SELTED_COURSE_REQUIRED_PAGENO,data)
            this.$store.commit(types.CLASS_DETAIL_SET_SELECTED_COURSE_INFORMATION,data)
            this.$store.commit(types.EXAM_HISTORY_EXAMPAPER,data)
            this.$store.commit(types.EXAM_PREVIEW_INFORMATION,data)
        }
    },
    mounted(){
        if(this.$store.state.trainClassDetailModule.isPullChildren){
            this.$store.commit(types.CD_LOADING_DATA,false);
        }else {
            this.requireClassDetail();
            this.requireCDCourseInformation();
            this.requireCDCourseList();
            this.requireCDExamList();
        }
    },
    destroyed(){
        clearInterval(this.timer);
    }
}

</script>

3.错误信息
2017-03-29 17:08:01.471 HBAccountant[9208:1982866] * Terminating app due to uncaught exception 'NSRangeException', reason: '-[__NSCFArray objectAtIndex:]: index (2) beyond bounds (2)'
* First throw call stack:
(

0   CoreFoundation                      0x000000010a284b0b __exceptionPreprocess + 171
1   libobjc.A.dylib                     0x00000001097e1141 objc_exception_throw + 48
2   CoreFoundation                      0x000000010a2ed625 +[NSException raise:format:] + 197
3   CoreFoundation                      0x000000010a225557 -[__NSCFArray objectAtIndex:] + 151
4   HBAccountant                        0x0000000102c92c0e rootNodeGetChild + 206
5   HBAccountant                        0x0000000102c481ca layoutNodeImpl + 1914
6   HBAccountant                        0x0000000102c4792f wx_layoutNode + 575
7   HBAccountant                        0x0000000102c921af -[WXComponentManager _layout] + 335
8   HBAccountant                        0x0000000102c91fab -[WXComponentManager _layoutAndSyncUI] + 43
9   HBAccountant                        0x0000000102c8c677 -[WXComponentManager _recursivelyAddComponent:toSupercomponent:atIndex:appendingInTree:] + 1543
10  HBAccountant                        0x0000000102c8c02b -[WXComponentManager addComponent:toSupercomponent:atIndex:appendingInTree:] + 1163
11  HBAccountant                        0x0000000102c543a3 __42-[WXBridgeContext registerGlobalFunctions]_block_invoke_2 + 147
12  HBAccountant                        0x0000000102c8ae64 +[WXComponentManager _performBlockOnComponentThread:] + 164
13  Foundation                          0x0000000105b72e51 __NSThreadPerformPerform + 334
14  CoreFoundation                      0x000000010a22ac01 __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__ + 17
15  CoreFoundation                      0x000000010a2100cf __CFRunLoopDoSources0 + 527
16  CoreFoundation                      0x000000010a20f5ff __CFRunLoopRun + 911
17  CoreFoundation                      0x000000010a20f016 CFRunLoopRunSpecific + 406
18  Foundation                          0x0000000105b26480 -[NSRunLoop(NSRunLoop) runMode:beforeDate:] + 274
19  HBAccountant                        0x0000000102c8ad8d -[WXComponentManager _runLoopThread] + 301
20  Foundation                          0x0000000105b35fb1 __NSThread__start__ + 1197
21  libsystem_pthread.dylib             0x000000010af439af _pthread_body + 180
22  libsystem_pthread.dylib             0x000000010af438fb _pthread_body + 0
23  libsystem_pthread.dylib             0x000000010af43101 thread_start + 13

)
libc++abi.dylib: terminating with uncaught exception of type NSException

  1. 目前尝试 将页面 一块一块注释掉来定位问题标签 可是由于崩溃不是每次都会重现 很难定位到具体哪一个标签,对源码进行断点调试,由于水平有限并没有找到该如何解决

阅读 2.7k
3 个回答

目前来看 是在rootNodeGetChild 函数中 发生数组越界的情况
即 (manager->_fixedComponents)(i-1)) 取值越界

i会大于 manager->_fixedComponents.count 引发的...这是目前的进展

很明显是获取某个节点的时候,数组下标越界了。首先要给这部分加个try catch不能渲染的数据出错就让APP崩溃啊……

写了错误捕捉以后,在catch里将HTML写入在线的日志中,分析出错时候的HTML中是不是有未闭合的标签,或者是该位置的内容为空等情况。

建议你先尝试下源码中添加越界保护试下,看下会有其他问题么

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进