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

SwiftUI小组件突发空白,寻求开发者解决方案

SwiftUI小组件突然空白的排查与解决建议

问题描述

此前正常运行的SwiftUI小组件突然显示空白,是否有其他开发者遇到该问题?

我开发了一款SwiftUI小组件,通过遍历字符串数组随机展示图片,该小组件此前运行正常,但现在无法正常显示。

相关代码

//
//  QuoteWidget.swift
//  QuoteWidget
//
//  Created by E2318556 on 27/6/2565 BE.
//

import WidgetKit
import SwiftUI

struct Provider: TimelineProvider {
    func placeholder(in context: Context) -> SimpleEntry {
        SimpleEntry(date: Date(), quotes: "7")
    }

    func getSnapshot(in context: Context, completion: @escaping (SimpleEntry) -> ()) {
        let entry = SimpleEntry(date: Date(), quotes: "7")
        completion(entry)
    }

    func getTimeline(in context: Context, completion: @escaping (Timeline<Entry>) -> ()) {
        var entries: [SimpleEntry] = []

        // Generate a timeline consisting of five entries an hour apart, starting from the current date.
        let currentDate = Date()
        for hourOffset in 0 ..< 1 {
            let entryDate = Calendar.current.date(byAdding: .hour, value: hourOffset, to: currentDate)!
            let entry = SimpleEntry(date: entryDate, quotes: MyDataProvider.getQuotes())
            entries.append(entry)
        }

        let timeline = Timeline(entries: entries, policy: .atEnd)
        completion(timeline)
    }
}

struct SimpleEntry: TimelineEntry {
    let date: Date
    let quotes: String
}

struct QuoteWidgetEntryView : View {
    var entry: Provider.Entry

    var body: some View {
        ZStack{
            Color.white.edgesIgnoringSafeArea(.all)
            Image(entry.quotes)
                .resizable()
                .ignoresSafeArea()
        }
    }
}

@main
struct QuoteWidget: Widget {
    let kind: String = "QuoteWidget"

    var body: some WidgetConfiguration {
        StaticConfiguration(kind: kind, provider: Provider()) { entry in
            QuoteWidgetEntryView(entry: entry)
        }
        .configurationDisplayName("WithU by Crying Cloud")
        .description("ตกแต่งหน้าจอโฮมด้วยข้อความเพิ่มกำลังใจ")
        .supportedFamilies([.systemSmall, .systemLarge])
    }
}

struct QuoteWidget_Previews: PreviewProvider {
    static var previews: some View {
        QuoteWidgetEntryView(entry: SimpleEntry(date: Date(), quotes: "4"))
            .previewContext(WidgetPreviewContext(family: .systemSmall))
    }
}

class MyDataProvider{
    static func getQuotes() -> String{
        let quotes = ["1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12", "13", "14", "15", "16", "17", "18", "19", "20", "21", "22", "23", "24", "25", "26", "27", "28", "29", "30", "31", "32", "33", "34", "35", "36", "37", "38", "39", "40", "41", "42", "43", "44", "45", "46", "47", "48", "49", "50", "51", "52", "53", "54", "55", "56", "57", "58", "59", "60", "61", "62", "63", "64", "65", "66", "67", "68", "69", "70", "71", "72", "73", "74", "75", "76", "77", "78", "79", "80", "81", "82", "83", "84", "85", "86", "87", "88", "89", "90", "91", "92", "93", "94", "95", "96", "97", "98", "99", "100", "101", "102", "103", "104", "105", "106", "107", "108", "109", "110"]
        
        return quotes.randomElement()!
        
    }
}

尝试过的方法

我曾尝试修改Widget结构体使用AnyView切换不同尺寸的视图,但没有解决问题,相关代码如下:

@main
struct QuoteWidget: Widget {
    let kind: String = "QuoteWidget"
    
    var body: some WidgetConfiguration {
        StaticConfiguration(kind: kind, provider: QuoteTimelineProvider()) { entry in
            if entry.date < Calendar.current.date(byAdding: .hour, value: 1, to: Date())! {
                AnyView(SmallQuoteWidgetView(entry: entry))
            } else {
                AnyView(LargeQuoteWidgetView(entry: entry))
            }
        }
        .configurationDisplayName("Quote Widget")
        .description("Displays a random quote")
        .supportedFamilies([.systemSmall, .systemLarge])
    }
}

排查方向与解决建议

1. 图片资源问题

  • 检查entry.quotes返回的字符串对应的图片是否存在于Widget target的资源文件中,确认资源的Target Membership已勾选Widget目标(主App和Widget是独立target,资源需要同步)。
  • 去掉randomElement()!的强制解包,数组为空或元素不存在时会直接崩溃,改用默认值兜底:
    static func getQuotes() -> String{
        let quotes = ["1", "2", ..., "110"]
        return quotes.randomElement() ?? "7" // 用默认图片名兜底
    }
    
  • 给图片添加占位背景色,排查是否是图片加载失败导致空白:
    Image(entry.quotes)
        .resizable()
        .ignoresSafeArea()
        .background(Color.gray) // 若显示灰色,说明图片未加载成功
    

2. Timeline刷新逻辑问题

  • 当前getTimeline只生成1个条目,且刷新策略.atEnd可能导致刷新不及时。可以调整为固定时间间隔刷新:
    let timeline = Timeline(entries: entries, policy: .after(entryDate.addingTimeInterval(3600))) // 1小时后自动刷新
    
  • 测试时手动触发刷新:长按Widget进入编辑模式,退出后会强制刷新Widget内容。

3. 布局与Target配置问题

  • 检查Widget的supportedFamilies是否和实际添加的Widget尺寸匹配,确保布局代码适配了Small和Large两种尺寸。
  • 清理项目缓存(Cmd+Shift+K),重启Xcode和设备,排除编译缓存导致的异常。
  • 确认Widget target的签名、权限配置和主App一致,证书过期或权限变更可能导致Widget无法正常运行。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.22 12:44:54