You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

iOS通知文本在部分设备显示为数字的问题排查求助

问题排查请求

我为通知类型创建了NotificationType枚举,用来告知用户有人关注、评论或点赞了帖子,每个枚举值对应对应的notificationMessage。大部分设备显示正常,但有iOS 16+的iPhone用户反馈,所有通知旁都显示“1”和“3”,和通知类型无关。我原本以为是枚举绑定的Int值问题,但不同类型通知显示相同数字,显然不是这个原因。已经检查过该用户的Firestore数据,和其他用户一致。现在因为只有部分设备出问题,完全没头绪,求排查思路。

异常显示效果

异常显示效果

预期显示效果

预期显示效果


Notification代码

struct Notification: Identifiable, Decodable {
    @DocumentID var id: String?
    
    var postId: String?
    let timestamp: Timestamp
    let type: NotificationType
    let uid: String
    
    var isFollowed: Bool? = false
    var post: Post?
    var user: User?
}

enum NotificationType: Int, Decodable {
    case like
    case comment
    case follow
    
    var notificationMessage: String {
        switch self {
        case .like: return " liked your post."
        case .comment: return " commented on your post."
        case .follow: return " followed you."
        }
    }
}

NotificationCell代码

struct NotificationsCell: View {
    @StateObject var viewModel: NotificationCellViewModel
    var isFollowed: Bool { return viewModel.notification.isFollowed ?? false}
    
    var body: some View {
        HStack (alignment: .top) {
            if let user = viewModel.notification.user {
                NavigationLink {
                    LazyView(ProfileView(user: user))
                } label: {
                    KFImage(URL(string: user.profileImageUrl))
                        .resizable()
                        .scaledToFill()
                        .frame(width: 48, height: 48)
                        .cornerRadius(6)
                }
            }
            
            if viewModel.notification.type != .follow {
                if let post = viewModel.notification.post {
                    NavigationLink {
                        ScrollView {
                            LazyView(FeedCell(viewModel: FeedCellViewModel(post: post)))
                        }
                    } label: {
                        Text("\(Text(viewModel.notification.user?.fullname ?? "").font   (Font.body2))\(Text(viewModel.notification.type.notificationMessage))\(Text(" "))\(Text((viewModel.timestampString)).foregroundColor(.gray).font(Font.footnote))")
                            .foregroundColor(Color(.label))
                            .font(Font.body)
                            .multilineTextAlignment(.leading)
                    }
                }
            } else {
                VStack (alignment: .leading, spacing: 8) {
                    if let user = viewModel.notification.user {
                        NavigationLink {
                            LazyView(ProfileView(user: user))
                        } label: {
                            Text("\(Text(user.fullname).font(Font.body2))\(Text(viewModel.notification.type.notificationMessage))\(Text(" "))\(Text((viewModel.timestampString)).foregroundColor(.gray).font(Font.footnote))")
                                .foregroundColor(Color(.label))
                                .font(Font.body)
                                .multilineTextAlignment(.leading)
                        }
                    }
                    HStack {
                        Button(action: {
                            isFollowed ? viewModel.unfollow() : viewModel.follow()
                        }, label: {
                            Text(isFollowed ? "Following" : "Follow Back")
                                .font(Font.button)
                                .padding(4)
                                .foregroundColor(isFollowed ? Color.accentColor: .white)
                                .background(isFollowed ? .white : Color.accentColor)
                        })
                        .cornerRadius(10)
                        .overlay(
                            RoundedRectangle(cornerRadius: 10)
                                .stroke(Color.accentColor, lineWidth: isFollowed ? 1 : 0)
                        )
                    }
                }
            }
            Spacer()
            
            if viewModel.notification.type != .follow {
                if let post = viewModel.notification.post {
                    NavigationLink {
                        ScrollView {
                            LazyView(FeedCell(viewModel: FeedCellViewModel(post: post)))
                        }
                    } label: {
                        KFImage(URL(string: viewModel.notification.post?.imageUrl ?? ""))
                            .resizable()
                            .scaledToFill()
                            .frame(width: 40, height: 48)
                            .cornerRadius(6)
                    }
                }
            }            
        }
        .padding(.vertical, 8)
        .padding(.horizontal)
    }
}

NotificationCellViewModel代码

class NotificationCellViewModel: ObservableObject {
    @Published var notification: Notification
    
    var timestampString: String {
        let formatter = DateComponentsFormatter()
        formatter.allowedUnits = [.second, .minute, .hour, .day, .weekOfMonth]
        formatter.maximumUnitCount = 1
        formatter.unitsStyle = .abbreviated
        return formatter.string(from: notification.timestamp.dateValue(), to: Date()) ?? ""
    }
    
    init(notification: Notification) {
        self.notification = notification
        checkIfUserIsFollowed()
        fetchNotificationPost()
        fetchNotificationUser()
    }
    
    func follow() {
        UserService.follow(uid: notification.uid) { _ in
            NotificationsViewModel.uploadNotification(toUid: self.notification.uid, type: .follow)
            self.notification.isFollowed = true
        }
    }
    
    func unfollow() {
        UserService.unfollow(uid: notification.uid) { _ in
            self.notification.isFollowed = false
        }
    }
    
    func checkIfUserIsFollowed() {
        guard notification.type == .follow else { return }
        UserService.checkIfUserIsFollowed(uid: notification.uid) { isFollowed in
            self.notification.isFollowed = isFollowed
        }
    }
    
    func fetchNotificationPost() {
        guard let postId = notification.postId else { return }
        
        COLLECTION_POSTS.document(postId).getDocument { snapshot, _ in
            self.notification.post = try? snapshot?.data(as: Post.self)
        }
    }
    
    func fetchNotificationUser() {
        COLLECTION_USERS.document(notification.uid).getDocument { snapshot, _ in
            self.notification.user = try? snapshot?.data(as: User.self)
        }
    }
}

排查思路

  1. iOS 16+的Text拼接兼容性问题:当前代码用了多层Text嵌套拼接的写法,iOS 16可能对这种组合逻辑有解析bug。建议改成直接用字符串拼接,再通过AttributedString或自定义Modifier设置不同部分的样式,避免嵌套Text组件。
  2. DateComponentsFormatter行为差异:用户看到的“1”“3”可能是时间格式化的异常输出。试试移除.weekOfMonth单位,或者换成DateFormatter测试,看是否还会出现奇怪的数字。
  3. 枚举解码兼容性:给NotificationType的rawValue显式赋值,避免iOS 16的Codable对隐式Int值解码出现异常:
    enum NotificationType: Int, Decodable {
        case like = 0
        case comment = 1
        case follow = 2
        // ...
    }
    
  4. KFImage加载异常:检查KFImage的配置,是否在iOS 16下加载失败时显示了默认数字占位符,尝试替换为本地占位图测试。
  5. 设备系统设置影响:让用户检查设备的语言、区域格式,特殊的日期/数字格式可能导致时间字符串显示异常。
  6. SwiftUI布局逻辑变更:iOS 16的SwiftUI对NavigationLink、Text布局有API变更,简化NotificationCell的嵌套结构,逐步排查是否是布局嵌套导致的渲染bug。

内容的提问来源于stack exchange,提问作者amelia

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.19 19:12:01