做了一个毒舌版 MBTI 测试 App,聊聊 16 种人格的数据建模、配对码编码方案和 ImageRenderer 踩坑

4 阅读8分钟

起因

去年底公司团建,有人拿 MBTI 测试结果当破冰话题,场面一度非常尴尬——大家对着一堆字母和学术描述,根本聊不起来。我当时就想:这东西如果换成毒舌风格的职场人话,是不是传播性会好很多?

于是花了两个多月,做了一个叫「NMTI人格测试」的 iOS App。核心思路就一句话:把 MBTI 的四个维度用职场场景题重新包装,结果不叫 INFJ、ENTP 这些,而是叫「六边形悍匪」「优雅吸血鬼」「金牌老黄牛」这类一眼能记住的标签。

做完之后觉得有几个技术点值得拿出来说说。

四维度打分与人格编码

传统 MBTI 有 E/I、S/N、T/F、J/P 四个维度,我没直接照搬,而是根据职场场景抽象了四个维度:C(掌控力)、S(社交策略)、E(执行力)、A(利他倾向)。每道题的选项对应不同维度加分,答完后按每个维度得分的高低各映射一个字母,四个字母拼成人格编码:

维度含义高分字母低分字母
C掌控力P(主动掌控)D(被动应对)
S社交策略R(关系驱动)L(独立行动)
E执行力E(高效执行)O(佛系摸鱼)
A利他倾向D(利己决断)S(利他服务)

拿「六边形悍匪」举例:四个维度全部高分 → P + R + E + D → 人格编码 PRED。反过来,四维度全低分 → D + L + O + S → DLOS,对应另一种人格。这样 2⁴ = 16 种组合,刚好覆盖 16 型人格。

数据结构本身很直白:

struct DimensionScores: Codable, Equatable {
    let c: Int  // 掌控力
    let s: Int  // 社交策略
    let e: Int  // 执行力
    let a: Int  // 利他倾向
}

struct ArchiveEntry: Identifiable, Equatable {
    let id: UUID
    var nickname: String
    let personalityCode: String  // "PRED", "VAMP", "WORK" 等
    let scores: DimensionScores
    let date: Date
    let pack: QuizPack  // 职场版 or 学生版
}

有个小坑值得说一下:后来加了「做题家版」(学生场景),老存档里没有 pack 字段,decode 时用 decodeIfPresent 做兼容,默认回退到职场版。这种事听起来不值一提,但不处理的话老用户升级直接 crash。

16 种人格的内容架构

说实话,技术上最不难的部分反而花了最多时间——写 16 种人格的文案。

每种人格有五个内容字段:title(标签名)、slogan(一句话毒舌)、tagline(海报用,约100字)、fullDesc(详情页400-500字),还有 rivalCodepartnerCode 做人格匹配。

比如「优雅吸血鬼」(VAMP) 的 slogan 是:

满嘴大局观,实则不干活,还能把锅甩得极其自然。

我试过用 AI 辅助生成文案,出来的东西全是"您拥有出色的领导力和战略思维"这种味道,根本用不了。最后还是手写了全部 16×2=32 套文案(职场版 + 学生版),前后改了大概四五稿,纯文案工作花了快三周。

其中最难写的是「赛博隐形人」(GOS)——这种人格的特点就是"没有存在感",但你得用文字写出"没有存在感是什么感觉",还得让读者觉得精准好笑。改了六七版,从"你像个NPC"到"你的存在感像空气——不缺,但平时感觉不到",才算找到那个点。

两个题包共享同一套人格编码,但文案完全不同。代码上通过 QuizPack 做分发:

extension Personality {
    func copy(for pack: QuizPack) -> PersonalityCopy {
        switch pack {
        case .workplace:
            return PersonalityCopy(slogan: slogan, tagline: tagline, fullDesc: fullDesc)
        case .student:
            return Self.studentCopy[id]
                ?? PersonalityCopy(slogan: slogan, tagline: tagline, fullDesc: fullDesc)
        }
    }
}

学生版文案后加的,用 Dictionary 做可选查找,找不到就 fallback 到职场版。比如 WORK(金牌老黄牛),职场版说"不仅被白嫖,还要把姿态摆得极其优美",学生版变成"不仅被全组安排,还要把姿态摆得极其优雅"——场景换了,人格内核没变。这样后面加新题包不需要改 Personality 主结构,只需要新增一个 xxxCopy 字典。

双人互测:6 位配对码的编码方案

「测朋友」功能是我觉得最有意思也最纠结的部分。

最初的方案是走自建后端,存测试链接、匹配双方结果、生成对比报告。做了一半算了下——服务器成本、接口维护、数据合规,对一个独立开发者来说太重了。

后来换了个思路:把双人匹配的信息压缩进一个 6 位短码,纯客户端完成编解码,零后端依赖。

6 位配对码的格式是这样的:

位置:  [1][2]  [3][4][5][6]
含义:  人格码   四维度分数
  • 第 1-2 位:人格编码的索引,用 Base36(0-9 + A-Z)表示。16 种人格用 2 位 Base36 绰绰有余(36² = 1296 种),第 1 位是人格索引,第 2 位做校验(索引值 mod 36 的偏移量),防止手动输入时打错一个字符就匹配到完全错误的人格。
  • 第 3-6 位:C/S/E/A 四个维度的得分,每个维度满分 10 分,各用一个 Base36 字符表示(0-9 直接映射,10 用 A)。

比如一个 PRED 用户,四维度得分是 C=8, S=7, E=9, A=6,生成的配对码就类似 A38796(A3 是 PRED 编码+校验,后四位是分数)。

A 把这个码发给 B,B 在 App 里输入后本地解码,拿到 A 的人格和各维度分数。B 自己做完测试后,App 在本地把两人的四维度分数拉在一起出雷达对比图,再根据 rivalCode / partnerCode 生成相处建议。

这个方案的好处是零运维成本。缺点很明显:B 必须也装了 App 才能参与,没法像 H5 链接那样直接打开就测。如果后面用户量真起来,可能还是得上 Web 版。但对 v1.0 来说,先跑起来比架构完美重要。

结果海报生成与 ImageRenderer 踩坑

海报是传播的关键物料——如果测完的结果图不够有趣、不够让人想截图发朋友圈,后面什么冷启动策略都是空谈。

技术上用 SwiftUI 的 ImageRenderer 把结果 View 渲染成图片,海报上放了人格标签、slogan、四维度雷达图。核心考量是:这张图发到群里,别人不需要任何解释就能 get 到笑点。

几个实战坑:

中英文混排的行高问题。 毒舌文案里经常有引号、破折号这类标点,中英混排时行高不一致,试了 lineSpacing 各种值都不理想,最后用固定 lineSpacing 加手动 padding 暴力对齐,不算优雅但视觉上过关了。

16 张人格插画尺寸不一。 海报模板要做自适应裁剪,用 aspectFill 配合固定画框解决。

ImageRenderer 在低内存设备概率性返回 nil。 这个坑是在 iPhone SE 2 上发现的,后台渲染时偶尔拿到空图片。处理方式比较粗暴——降低输出分辨率重试:

func renderPoster(view: some View) -> UIImage? {
    let renderer = ImageRenderer(content: view)
    renderer.scale = 3.0
    if let img = renderer.uiImage { return img }
    // SE2 等低内存设备 scale=3 偶尔失败,降级重试
    renderer.scale = 2.0
    return renderer.uiImage
}

在 SE2 上实测,scale=3 的失败率大概 15% 左右(测了约 40 次),降到 scale=2 之后没再遇到过 nil。如果 scale=2 也失败就弹 toast 让用户手动截屏——这种情况我自己没复现过,算是兜底。

说实话有点粗糙,理想方案应该是用 UIGraphicsImageRenderer 做离屏渲染绕开 ImageRenderer 的内存问题,但那样就得把 SwiftUI 的海报布局在 Core Graphics 层重写一遍,投入产出比不划算,先这样了。

目前的状况

刚上线一周,下载量基本是零。冷启动确实难,测试类 App 没有社交裂变跑起来,靠 App Store 自然流量几乎不可能。

我在想的几个方向:

  • 海报加二维码:目前分享出去的图片没有下载入口,算是个明显的遗漏
  • Web 版:做一个 H5 把核心测试流程搬上去,不用装 App 就能测,结果页再引导下载看完整分析
  • 内容运营:把 16 种人格的毒舌描述做成系列内容发出去,比纯推广 App 有效得多

整个项目算下来,Swift 代码写了大概三周,UI 调了一周,32 套人格文案写了三周改了五稿,图片素材和海报模板折腾了一周。代码量不大,但内容创作的时间占了将近一半。对于测试类产品来说,文案质量直接决定传播率——如果结果描述不够精准、不够让人想截图转发,技术做得再好也白搭。

App Store 搜「NMTI人格测试」可以试试你是哪种职场人格。如果你也在做测试类或轻社交产品,评论区聊聊冷启动的经验,我是真的需要。