was mutated while being enumerated.-terminate called throwing&nbsp

本文分析了一款iPad应用在下载过程中出现的崩溃问题。通过跟踪发现,在更新下载进度的同时,另一个定时器正在清理并重新填充UIScrollView,导致多线程并发访问冲突。最终通过避免多线程同时修改同一对象解决了问题。
遇到一个问题,跟踪了半天才发现原因。(现象是,客户老是说在下载的过程中,过一会就出现崩溃的现象, 只要点了下载按钮, 不做任何操作, 然后期刊就开始正常下载了,过大概5分钟后,再去看,程序就已经崩溃了)
在做《时装传媒》ipad应用时,首页的下载页面,下载时,会不断地去更新页面上的下载进度,同时还有一个15秒的timer, 会每15秒切换当前显示的是男装,女装或者艺术刊页面。这个timer会把当前的scrollView中显示的封面图片进行移除,然后再替换,以实现自动更换首页封面的功能

崩溃时提示:
Collection <UIButtonContent: 0x2341234> was mutated while being enumerated
(在网上搜了一下,发现有一个类似的问题:'NSGenericException', reason: '*** Collection <__NSArrayM: 0x8ef350> was mutated while being enumerated.')


根据这个提示, 想了一下,觉得应该在做遍历的过程中,修改了这个NSArray或者是NSMutableArray。后来想想, 这可能是多线程并发访问时出现的问题, 沿崩溃时的堆栈找了一下,果然找到。


因为我们在下载时, 使用了Block每当接受到数据,就去更新一下一个UIScrollView中的下载进度条的百分比。

而另有一个NSTimer, 会隔一段时间把这个UIScrollView中的全部元素清空,然后再重新添加, 因为可能有动态的元素需要添加或者删除。


运行时, 就会出现,两个线程同时去访问的情况, 当Block正在去更新UIScrollView中的这个元素时, NSTimer中可能正在执行清除操作,所以就崩了。


原来,在同一时间,不同的线程同时读取和修改了NSMutaleArray。


解决办法:避免多线程同时去修改一个对象, 避免做遍历时,这个对象被修改,根据这个思想,可以考虑加锁,或者直接使用atomic的方式来做。

<template> <div> <!-- 图片上传组件辅助--> <el-upload class="avatar-uploader" :action="getActionUrl" name="file" :headers="header" :show-file-list="false" :on-success="uploadSuccess" :on-error="uploadError" :before-upload="beforeUpload" ></el-upload> <quill-editor class="editor" v-model="value" ref="myQuillEditor" :options="editorOption" @blur="onEditorBlur($event)" @focus="onEditorFocus($event)" @change="onEditorChange($event)" ></quill-editor> </div> </template> <script> // 工具栏配置 const toolbarOptions = [ ["bold", "italic", "underline", "strike"], // 加粗 斜体 下划线 删除线 ["blockquote", "code-block"], // 引用 代码块 [{ header: 1 }, { header: 2 }], // 1、2 级标题 [{ list: "ordered" }, { list: "bullet" }], // 有序、无序列表 [{ script: "sub" }, { script: "super" }], // 上标/下标 [{ indent: "-1" }, { indent: "+1" }], // 缩进 [{ size: ["small", false, "large", "huge"] }], // 字体大小 [{ header: [1, 2, 3, 4, 5, 6, false] }], // 标题 [{ color: [] }, { background: [] }], // 字体颜色、字体背景颜色 [{ font: [] }], // 字体种类 [{ align: [] }], // 对齐方式 ["clean"], // 清除文本格式 ["link", "image", "video"] // 链接、图片、视频 ]; import config from "@/config/config"; import { quillEditor } from "vue-quill-editor"; import "quill/dist/quill.core.css"; import "quill/dist/quill.snow.css"; import "quill/dist/quill.bubble.css"; export default { props: { /*编辑器的内容*/ value: { type: String }, action: { type: String }, /*图片大小*/ maxSize: { type: Number, default: 4000 //kb } }, components: { quillEditor }, data() { return { baseUrl: config.baseUrl, baseUrl2: config.name, content: this.value, quillUpdateImg: false, // 根据图片上传状态来确定是否显示loading动画,刚开始是false,不显示 editorOption: { placeholder: "", theme: "snow", // or 'bubble' modules: { toolbar: { container: toolbarOptions, handlers: { image: function(value) { if (value) { // 触发input框选择图片文件 document.querySelector(".avatar-uploader input").click(); } else { this.quill.format("image", false); } } } } } }, header: { 'Token': localStorage.getItem('frontToken') } // 有的图片服务器要求请求头需要有token }; }, computed: { // 计算属性的 getter getActionUrl: function() { return this.baseUrl2 + '/' + this.action; } }, methods: { onEditorBlur() { //失去焦点事件 }, onEditorFocus() { //获得焦点事件 }, onEditorChange() { console.log(this.value); //内容改变事件 this.$emit("input", this.value); }, // 富文本图片上传前 beforeUpload() { // 显示loading动画 this.quillUpdateImg = true; }, uploadSuccess(res, file) { // res为图片服务器返回的数据 // 获取富文本组件实例 let quill = this.$refs.myQuillEditor.quill; // 如果上传成功 if (res.code === 0) { // 获取光标所在位置 let length = quill.getSelection().index; // 插入图片 res.url为服务器返回的图片地址 quill.insertEmbed(length, "image", this.baseUrl+ "upload/" +res.file); // 调整光标到最后 quill.setSelection(length + 1); } else { this.$message.error("图片插入失败"); } // loading动画消失 this.quillUpdateImg = false; }, // 富文本图片上传失败 uploadError() { // loading动画消失 this.quillUpdateImg = false; this.$message.error("图片插入失败"); } } }; </script> <style> .editor { line-height: normal !important; } .ql-snow .ql-tooltip[data-mode="link"]::before { content: "请输入链接地址:"; } .ql-snow .ql-tooltip.ql-editing a.ql-action::after { border-right: 0px; content: "保存"; padding-right: 0px; } .ql-snow .ql-tooltip[data-mode="video"]::before { content: "请输入视频地址:"; } .ql-container { height: 400px; } .ql-snow .ql-picker.ql-size .ql-picker-label::before, .ql-snow .ql-picker.ql-size .ql-picker-item::before { content: "14px"; } .ql-snow .ql-picker.ql-size .ql-picker-label[data-value="small"]::before, .ql-snow .ql-picker.ql-size .ql-picker-item[data-value="small"]::before { content: "10px"; } .ql-snow .ql-picker.ql-size .ql-picker-label[data-value="large"]::before, .ql-snow .ql-picker.ql-size .ql-picker-item[data-value="large"]::before { content: "18px"; } .ql-snow .ql-picker.ql-size .ql-picker-label[data-value="huge"]::before, .ql-snow .ql-picker.ql-size .ql-picker-item[data-value="huge"]::before { content: "32px"; } .ql-snow .ql-picker.ql-header .ql-picker-label::before, .ql-snow .ql-picker.ql-header .ql-picker-item::before { content: "文本"; } .ql-snow .ql-picker.ql-header .ql-picker-label[data-value="1"]::before, .ql-snow .ql-picker.ql-header .ql-picker-item[data-value="1"]::before { content: "标题1"; } .ql-snow .ql-picker.ql-header .ql-picker-label[data-value="2"]::before, .ql-snow .ql-picker.ql-header .ql-picker-item[data-value="2"]::before { content: "标题2"; } .ql-snow .ql-picker.ql-header .ql-picker-label[data-value="3"]::before, .ql-snow .ql-picker.ql-header .ql-picker-item[data-value="3"]::before { content: "标题3"; } .ql-snow .ql-picker.ql-header .ql-picker-label[data-value="4"]::before, .ql-snow .ql-picker.ql-header .ql-picker-item[data-value="4"]::before { content: "标题4"; } .ql-snow .ql-picker.ql-header .ql-picker-label[data-value="5"]::before, .ql-snow .ql-picker.ql-header .ql-picker-item[data-value="5"]::before { content: "标题5"; } .ql-snow .ql-picker.ql-header .ql-picker-label[data-value="6"]::before, .ql-snow .ql-picker.ql-header .ql-picker-item[data-value="6"]::before { content: "标题6"; } .ql-snow .ql-picker.ql-font .ql-picker-label::before, .ql-snow .ql-picker.ql-font .ql-picker-item::before { content: "标准字体"; } .ql-snow .ql-picker.ql-font .ql-picker-label[data-value="serif"]::before, .ql-snow .ql-picker.ql-font .ql-picker-item[data-value="serif"]::before { content: "衬线字体"; } .ql-snow .ql-picker.ql-font .ql-picker-label[data-value="monospace"]::before, .ql-snow .ql-picker.ql-font .ql-picker-item[data-value="monospace"]::before { content: "等宽字体"; } </style>报错vue.runtime.esm.js:4674 [Vue warn]: Avoid mutating a prop directly since the value will be overwritten whenever the parent component re-renders. Instead, use a data or computed property based on the prop’s value. Prop being mutated: “value”
最新发布
09-12
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值