self表示的是当前类开辟内存的对象(文档里写的是当前的消息接受者 Return Value: The receiver.)

本文深入解析了Objective-C中的self与super在实例方法与类方法中的使用方式,阐述了它们如何在对象间传递消息以及在调用父类方法时的流程。通过实例说明了self与_cmd参数在方法调用过程中的角色,并强调了消息转发机制在对象层次中的作用。


答疑:当在子类中调用super跳到父类中执行self时,其self实际指向的是子类(比如self.或者[self doSomething]等),当在子类里找不到这个属性或者方法时,会到父类中去中,如果还找不到,就会执行消息转发,转发失败则crash


(实例方法中的self,是对象首地址;类方法中的self,是class


self表示的是当前类开辟内存的对象(文档里写的是当前的消息接受者 Return Value: The receiver.


super是一个编译器指示符,当调用super时,会给当前receiver发送消息,我要调用父类的方法,然后才回去父类的方法列表中查找方法


所以调用[super class]时,其实是当前类,因为接收消息的是当前类


self_cmd都是当前类的隐藏参数_cmd表示当前的方法selector


效果未实现,我手动修改数据库已有条目信息,前端未能够实时监听。 前端代码:// pages/order-detail/order-detail.js Page({ data: { activeIndex: 0, // 当前选中的状态索引 statusList: ['新订单', '备货中', '待配送', '配送中', '已完成', '已取消'], // 订单状态列表 showActionSheet: false, // 是否显示操作面板 currentOrderId: null, // 当前操作的订单ID cancelOrderCount: 0, // 取消订单次数 lastCancelDate: null, // 最后一次取消订单的日期 searchText: '', // 搜索关键字 orders: [], // 所有订单数据 filteredOrders: [], // 筛选后的订单数据 isLoading: false, // 是否正在加载数据 page: 1, // 当前页码 pageSize: 10, // 每页大小 hasMore: true ,// 是否还有更多数据 socketOpen: false, // WebSocket 是否已打开 socketTask: null, // WebSocket 实例 }, // onLoad() { // this.loadOrders(); // 加载订单数据 // this.loadCancelInfo(); // 加载取消订单信息 // }, onReachBottom() { if (this.data.hasMore && !this.data.isLoading) { this.setData({ page: this.data.page + 1 }, () => { this.loadOrders(); }); } }, loadCancelInfo() { const cancelInfo = wx.getStorageSync('cancelOrderInfo') || {}; this.setData({ cancelOrderCount: cancelInfo.count || 0, lastCancelDate: cancelInfo.date || null }); }, onLoad() { this.loadOrders(); // 加载订单数据 this.initWebSocket(); // 初始化 WebSocket }, onUnload() { this.closeWebSocket(); // 页面卸载时关闭 WebSocket }, // 初始化 WebSocket // pages/order-detail/order-detail.js initWebSocket() { const that = this; const socketTask = wx.connectSocket({ url: 'ws://127.0.0.1:8001/ws/orders/', header: { 'Authorization': 'Bearer ' + wx.getStorageSync('token') } }); socketTask.onOpen(() => { console.log('WebSocket 已连接'); that.setData({ socketOpen: true }); }); socketTask.onMessage((res) => { console.log('收到新订单:', res.data); const newOrder = JSON.parse(res.data); // 更新本地订单数据 that.setData({ orders: [newOrder, ...that.data.orders], filteredOrders: [newOrder, ...that.data.filteredOrders] }); // 提示用户有新订单 wx.showToast({ title: '有新订单', icon: 'success' }); }); socketTask.onError((err) => { console.error('WebSocket 连接错误:', err); that.setData({ socketOpen: false }); }); socketTask.onClose(() => { console.log('WebSocket 已关闭'); that.setData({ socketOpen: false }); }); this.setData({ socketTask }); }, // 关闭 WebSocket closeWebSocket() { const { socketTask } = this.data; if (socketTask) { socketTask.close(); } }, async loadOrders() { if (this.data.isLoading || !this.data.hasMore) return; this.setData({ isLoading: true }); try { const { statusList, activeIndex, searchText, page, pageSize } = this.data; const currentStatus = statusList[activeIndex]; const user = wx.getStorageSync('userInfo'); const shopId = user.id; // 确保已存储shopId const res = await new Promise((resolve, reject) => { wx.request({ url: 'http://127.0.0.1:8000/api/gouw/merchant/orders/', method: 'GET', header: { 'Authorization': 'Bearer ' + wx.getStorageSync('token'), 'Content-Type': 'application/json' }, data: { shop_id: shopId, status: currentStatus, search: searchText, page: page, page_size: pageSize }, success: (res) => { if (res.statusCode === 200) { resolve(res.data); } else { reject(new Error(`HTTP ${res.statusCode}: ${res.data?.message || '请求失败'}`)); } }, fail: (err) => { reject(new Error('网络请求失败')); } }); }); console.log('API响应数据:', JSON.stringify(res, null, 2)); if (res.code === 200) { const newOrders = res.data.orders.map(order => ({ id: order.orderId, orderId: order.orderNo, customerName: order.customerName, customerPhone: order.customerPhone, status: order.status, statusCode: order.statusCode, createTime: order.createTime, totalAmount: order.totalAmount, products: order.products, deliveryFee: order.deliveryFee })); this.setData({ orders: page === 1 ? newOrders : [...this.data.orders, ...newOrders], filteredOrders: page === 1 ? newOrders : [...this.data.orders, ...newOrders], hasMore: page < res.data.pagination.totalPages, isLoading: false }); } else { throw new Error(res.message || '加载订单失败'); } } catch (err) { console.error('加载订单错误:', err.message, err); wx.showToast({ title: err.message || '加载订单失败', icon: 'none', duration: 2000 }); this.setData({ isLoading: false }); } }, // 加载订单数据 // async loadOrders() { // try { // const user = wx.getStorageSync('userInfo'); // const shopId = user.id; // const res = await new Promise((resolve, reject) => { // wx.request({ // url: 'http://127.0.0.1:8000/api/gouw/merchant/orders/', // method: 'GET', // header: { // 'Authorization': 'Bearer ' + wx.getStorageSync('token'), // 'Content-Type': 'application/json' // }, // data: { // shop_id: shopId, // status: '新订单', // page: 1, // page_size: 10 // }, // success: (res) => { // if (res.statusCode === 200) { // resolve(res.data); // } else { // reject(new Error(`HTTP ${res.statusCode}: ${res.data?.message || '请求失败'}`)); // } // }, // fail: (err) => { // reject(new Error('网络请求失败')); // } // }); // }); // if (res.code === 200) { // const orders = res.data.orders.map(order => ({ // id: order.orderId, // orderId: order.orderNo, // customerName: order.customerName, // customerPhone: order.customerPhone, // status: order.status, // statusCode: order.statusCode, // createTime: order.createTime, // totalAmount: order.totalAmount, // products: order.products, // deliveryFee: order.deliveryFee // })); // this.setData({ // orders, // filteredOrders: orders // }); // } // } catch (err) { // console.error('加载订单错误:', err.message); // } // }, // 切换订单状态 switchStatus(e) { const index = e.currentTarget.dataset.index; this.setData({ activeIndex: index, searchText: '', page: 1, hasMore: true }, () => { this.loadOrders(); }); }, filterOrders() { const { activeIndex, statusList, orders, searchText } = this.data; const currentStatus = statusList[activeIndex]; let filtered = orders.filter(order => { if (currentStatus !== '全部' && order.status !== currentStatus) { return false; } if (searchText && !order.orderId.includes(searchText) && !order.customerName.includes(searchText) && !order.customerPhone.includes(searchText)) { return false; } return true; }); filtered.sort((a, b) => new Date(b.createTime) - new Date(a.createTime)); this.setData({ filteredOrders: filtered }); }, handleSearchInput(e) { this.setData({ searchText: e.detail.value }); }, handleSearch() { this.setData({ page: 1, hasMore: true }, () => { this.loadOrders(); }); }, showActionSheet(e) { const orderId = e.currentTarget.dataset.orderid; this.setData({ showActionSheet: true, currentOrderId: orderId }); }, hideActionSheet() { this.setData({ showActionSheet: false, currentOrderId: null }); }, handleCancelOrder(e) { const orderId = e.currentTarget.dataset.orderid; const today = new Date().toDateString(); if (this.data.lastCancelDate === today && this.data.cancelOrderCount >= 3) { wx.showModal({ title: '提示', content: '当天取消接单次数已经用完,如需继续,请点击申诉', showCancel: false }); this.hideActionSheet(); return; } let newCount = this.data.cancelOrderCount; let newDate = this.data.lastCancelDate; if (newDate !== today) { newCount = 0; newDate = today; } newCount++; this.setData({ cancelOrderCount: newCount, lastCancelDate: newDate }); wx.setStorageSync('cancelOrderInfo', { count: newCount, date: newDate }); this.updateOrderStatus(orderId, '已取消'); wx.showToast({ title: '订单已取消', icon: 'success' }); this.hideActionSheet(); }, handleAppeal(e) { const orderId = e.currentTarget.dataset.orderid; this.hideActionSheet(); wx.navigateTo({ url: `/pages/appeal/appeal?orderId=${orderId}`, success: () => { console.log('跳转到申诉页面'); }, fail: (err) => { console.error('跳转失败:', err); wx.showToast({ title: '跳转失败,请重试', icon: 'none' }); } }); }, handleAcceptOrder(e) { const orderId = e.currentTarget.dataset.orderid; this.updateOrderStatus(orderId, '备货中'); wx.showToast({ title: '接单成功', icon: 'success' }); }, handleReadyForDelivery(e) { const orderId = e.currentTarget.dataset.orderid; this.updateOrderStatus(orderId, '待配送'); wx.showToast({ title: '备货完成', icon: 'success' }); }, handleStartDelivery(e) { const orderId = e.currentTarget.dataset.orderid; this.updateOrderStatus(orderId, '配送中'); wx.showToast({ title: '开始配送', icon: 'success' }); }, handleCompleteDelivery(e) { const orderId = e.currentTarget.dataset.orderid; this.updateOrderStatus(orderId, '已完成'); wx.showToast({ title: '配送完成', icon: 'success' }); }, // 更新订单状态 async updateOrderStatus(orderId, newStatus) { const token = wx.getStorageSync('token'); if (!token) { wx.showToast({ title: '未登录,请重新登录', icon: 'none' }); return; } wx.showLoading({ title: '处理中...', mask: true }); try { const res = await new Promise((resolve, reject) => { wx.request({ url: 'http://127.0.0.1:8000/api/gouw/update-order-status/', method: 'POST', header: { 'Authorization': 'Bearer ' + token, 'Content-Type': 'application/json' }, data: { order_no: orderId, status: newStatus }, success: (res) => { if (res.statusCode === 200 && res.data.code === 200) { resolve(res.data); } else { reject(new Error(res.data?.message || '更新失败')); } }, fail: (err) => { reject(new Error('网络请求失败')); } }); }); wx.hideLoading(); wx.showToast({ title: '操作成功', icon: 'success' }); // 从本地数据中移除已处理的订单 // 核心修改:更新本地订单状态并重新过滤 const updatedOrders = this.data.orders.map(order => { if (order.orderId === orderId) { return { ...order, status: newStatus }; } return order; }); this.setData({ // 从完整订单列表移除 orders: this.data.orders.filter(order => order.orderId !== orderId), // 从当前视图列表直接移除 filteredOrders: this.data.filteredOrders.filter(order => order.orderId !== orderId) }); wx.hideLoading(); wx.showToast({ title: '操作成功', icon: 'success' }); // this.loadOrders(); // 如果需要重新加载数据,可以调用 this.loadOrders(); } catch (err) { console.error('更新订单状态失败:', err.message); wx.hideLoading(); wx.showToast({ title: err.message || '操作失败,请重试', icon: 'none' }); } }, // 辅助方法:匹配搜索条件 matchSearchCriteria(order) { const searchText = this.data.searchText.toLowerCase(); return !searchText || order.orderId.toLowerCase().includes(searchText) || order.customerName.toLowerCase().includes(searchText) || order.customerPhone.includes(searchText); }, sj_mb(e) { wx.navigateTo({ url: "/pages/gr_xx/gr_xx", success: () => { console.log('成功跳转到商家信息页面'); }, fail: (err) => { console.error('跳转失败:', err); wx.showToast({ title: '跳转失败,请重试', icon: 'none' }); } }); }, dp_zt(e) { wx.navigateTo({ url: "/pages/dp_zt/dp_zt", success: () => { console.log('成功跳转到商家信息页面'); }, fail: (err) => { console.error('跳转失败:', err); wx.showToast({ title: '跳转失败,请重试', icon: 'none' }); } }); }, tk_dd(e) { wx.navigateTo({ url: "/pages/tk_dd/tk_dd", success: () => { console.log('成功跳转到退款订单页面'); }, fail: (err) => { console.error('跳转失败:', err); wx.showToast({ title: '跳转失败,请重试', icon: 'none' }); } }); } }); 后端代码:# DjangoProject1/asgi.py import os from django.core.asgi import get_asgi_application from channels.routing import ProtocolTypeRouter, URLRouter from .routing import application # 直接导入主路由配置 os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'DjangoProject1.settings') application = application # DjangoProject1/routing.py from django.urls import re_path from channels.routing import ProtocolTypeRouter, URLRouter from gouw.routing import websocket_urlpatterns as gouw_routes # 直接导入子路由 application = ProtocolTypeRouter({ "websocket": URLRouter([ re_path(r'^ws/', URLRouter(gouw_routes)), # 确保路径匹配 ]) }) # gouw/consumers.py import json from channels.generic.websocket import AsyncWebsocketConsumer from asgiref.sync import async_to_sync from channels.layers import get_channel_layer class OrderConsumer(AsyncWebsocketConsumer): async def connect(self): # 接受 WebSocket 连接 await self.accept() # 将用户加入组 await self.channel_layer.group_add("orders", self.channel_name) async def disconnect(self, close_code): # 用户断开连接时从组中移除 await self.channel_layer.group_discard("orders", self.channel_name) async def receive(self, text_data): # 接收来自客户端的消息 text_data_json = json.loads(text_data) message = text_data_json['message'] await self.channel_layer.group_send( "orders", { 'type': 'order_message', 'message': message } ) async def order_message(self, event): # 处理来自组的消息并发送给客户端 message = event['message'] await self.send(text_data=json.dumps({ 'message': message })) # 广播新订单 def broadcast_new_order(order_data): channel_layer = get_channel_layer() async_to_sync(channel_layer.group_send)( "orders", { 'type': 'order_message', 'message': order_data } ) # gouw/routing.py from django.urls import path from .consumers import OrderConsumer websocket_urlpatterns = [ path('orders/', OrderConsumer.as_asgi()), # 保持简单路由列表 ] # gouw/signals.py from django.db.models.signals import post_save, post_delete from django.dispatch import receiver from .models import Order from .consumers import broadcast_new_order @receiver(post_save, sender=Order) def order_saved(sender, instance, created, **kwargs): """ 当订单保存时触发此信号。 如果是新创建的订单,则广播消息。 """ if created: print(f"New order created: {instance}") broadcast_new_order({ "id": instance.id, "orderNo": instance.orderNo, "status": instance.status, "createTime": str(instance.createTime), "totalAmount": instance.totalAmount, "customerName": instance.customerName, "customerPhone": instance.customerPhone }) @receiver(post_delete, sender=Order) def order_deleted(sender, instance, **kwargs): """ 当订单删除时触发此信号。 可以选择广播删除消息。 """ print(f"Order deleted: {instance}")
05-17
<think> 根据代码片段,问题在于赋值时使用了`receiveUserList.value[0].id`和`receiveUserList.value[0].receiverTel`,但`receiveUserList`已经被映射为一个包含`label`和`value`的对象数组。然而,原始数据中的字段是`id`和`receiverTel`,但在映射后,数组中的每个对象变成了`{ label: item.receiver, value: item.id }`,所以原始数据中的`receiverTel`字段在映射后的对象中不存在。 因此,在设置`materialApplyFormState.receiverId`和`materialApplyFormState.receiverTel`时,不能直接从映射后的数组元素中取`receiverTel`(因为映射后的对象没有这个属性),而应该从原始数据`res.data[0].receiverList`中获取。 ### 修改方案 1. 在映射`receiveUserList`的同时,保留`receiverTel`字段。 2. 或者在映射后的数组中增加`receiverTel`字段。 ### 修改后的代码 ```javascript receiveUserList.value = res.data[0].receiverList.map(item => { return { label: item.receiver, value: item.id, tel: item.receiverTel // 将receiverTel也放入映射后的对象中 } }); if (receiveUserList.value && receiveUserList.value.length > 0) { materialApplyFormState.receiverId = receiveUserList.value[0].value; // 注意这应该是value,因为映射后的对象中id对应的是value materialApplyFormState.receiverTel = receiveUserList.value[0].tel; // 使用新增的tel字段 } ``` ### 解释 - 在映射时,除了`label`和`value`,我们增加了一个`tel`属性来保存电话号码。 - 这样,在设置`materialApplyFormState`时,就可以从映射后的数组元素中直接获取`tel`属性。 ### 另外注意 原始代码中`materialApplyFormState.receiverId`赋值用的是`receiveUserList.value[0].id`,但映射后的对象中并没有`id`属性,而是用`value`来存储原来的`id`。因此,我们改为`receiveUserList.value[0].value`。 ### 完整代码块修改 ```javascript changeLocation = (locationId) => { server.getLocationDropList({ id: locationId }) .then(res => { // 映射时保留电话号码 receiveUserList.value = res.data[0].receiverList.map(item => ({ label: item.receiver, value: item.id, tel: item.receiverTel })); if (receiveUserList.value && receiveUserList.value.length > 0) { materialApplyFormState.receiverId = receiveUserList.value[0].value; // 使用value materialApplyFormState.receiverTel = receiveUserList.value[0].tel; // 使用tel } }); } ``` ### 后续问题 在`changeReceiver`函数中,我们也需要修改,因为之前是直接从`receiveUserList.value`中查找`id`,现在映射后的对象中`id`变成了`value`属性,并且我们增加了`tel`属性。因此,`changeReceiver`函数可以保持不变,因为我们在映射时已经将`item.id`作为`value`,而`changeReceiver`函数中是通过`value`(即`receiverId`)来查找的,并且我们使用`tel`属性来设置电话号码。 但是,在`changeReceiver`函数中,我们使用了`receiveUserList.value`中的`receiverTel`字段,现在这个字段已经不存在了,所以需要修改为使用`tel`字段。 ### 修改changeReceiver函数 ```javascript const changeReceiver = (receiverId) => { // 注意:receiveUserList.value中的每个元素现在有label, value, tel三个属性 const matchedUser = receiveUserList.value.find(user => user.value === receiverId); if (matchedUser) { materialApplyFormState.receiverTel = matchedUser.tel; } } ``` ### 总结 1. 在映射接收人列表时,保留电话号码字段(使用`tel`属性)。 2. 在设置默认接收人时,使用`value`和`tel`。 3. 在`changeReceiver`中,根据选中的`receiverId`(即`value`)查找对应的对象,然后取`tel`属性。 这样修改后,电话号码的赋值就正确了。 §§相关问题§§ 1. 为什么在映射接收人列表时需要额外添加`tel`属性? 2. 在`changeReceiver`函数中,如何根据选中的接收人更新电话号码? 3. 如果接收人列表中没有电话号码字段,应如何处理? 4. 如何确保在改变送达位置时,接收人列表更新后自动选中第一个接收人并更新电话号码? 5. 在材料申请提交时,如何验证接收人电话号码的必填性? </think> 根据您的需求,需要修改接收人列表的赋值逻辑,确保使用映射后对象的`value`属性(即`item.id`)而不是直接使用原始`id`字段。以下是修改后的代码: ### 修改方案 ```javascript receiveUserList.value = res.data[0].receiverList.map(item => { return { label: item.receiver, value: item.id // 将id映射为value } }) if (receiveUserList.value && receiveUserList.value.length > 0) { // 使用映射后对象value属性(即item.id) materialApplyFormState.receiverId = receiveUserList.value[0].value; materialApplyFormState.receiverTel = res.data[0].receiverList[0].receiverTel; } ``` ### 修改说明 1. **映射处理**: - 在`receiveUserList`映射时,将`item.id`映射为`value`属性 - 保持`item.receiver`映射为`label`属性 2. **赋值逻辑**: - `materialApplyFormState.receiverId`:使用`receiveUserList.value[0].value`获取映射后的值 - `materialApplyFormState.receiverTel`:直接从原始数据`res.data[0].receiverList[0].receiverTel`获取(因为电话字段不需要映射) 3. **保持一致性**: - 在`changeReceiver`函数中也应统一使用`value`属性: ```javascript const changeReceiver = (receiverId) => { const matchedUser = receiveUserList.value.find(user => user.value === receiverId); if (matchedUser) { const originalUser = res.data[0].receiverList.find(item => item.id === receiverId); materialApplyFormState.receiverTel = originalUser?.receiverTel || ""; } } ``` ### 原因分析 原始代码直接使用`receiveUserList.value[0].id`的问题在于: 1. `receiveUserList`是映射后的数组,原始字段名`id`已映射为`value` 2. 映射后对象不再包含原始字段名,只有`label`和`value`属性 3. 直接访问`id`会返回`undefined` ### 完整修改示例 ```javascript changeLocation = (locationId) => { server.getLocationDropList({ id: locationId }) .then(res => { // 映射接收人列表 receiveUserList.value = res.data[0].receiverList.map(item => ({ label: item.receiver, value: item.id // 关键修改:将id映射为value })) // 设置默认接收人 if (receiveUserList.value.length > 0) { materialApplyFormState.receiverId = receiveUserList.value[0].value; // 从原始数据获取电话号码 materialApplyFormState.receiverTel = res.data[0].receiverList[0].receiverTel; } }) } ``` ### 注意事项 1. 确保所有使用`receiverId`的地方都基于`value`属性 2. 电话号码等未映射字段需直接从原始数据获取 3. 当接收人数据变更时,同步更新原始数据引用
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值