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

Swift开发提醒应用时出现Argument type 'Any'预期为类或类约束类型实例错误该如何解决?

解决Swift中「Argument type 'Any' expected to be an instance of a class or class-constrained type」编译器报错

问题场景

我正在开发一款提醒应用,在编写prepare(for:sender:)函数时遇到了编译器报错,错误信息是:Argument type 'Any' expected to be an instance of a class or class-constrained type。我的代码如下:

override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
    if saveButton === sender {
        let name = reminderTextField.text
        var time = timePicker.date
        let timeInterval = floor(time.timeIntervalSinceReferenceDate/60)*60
        time = NSDate(timeIntervalSinceReferenceDate: timeInterval) as Date
        //build; notification
        let notification = UILocalNotification()
        notification.alertTitle = "Reminder"
        notification.alertBody = "Don't forget to \(name!)!"
        notification.fireDate = time
        notification.soundName = UILocalNotificationDefaultSoundName
        UIApplication.shared.scheduleLocalNotification(notification)
        reminder = Reminder(name: name!, time: time as NSDate, notification: notification)
    }
}

问题根源

你遇到的这个报错,核心原因是**UILocalNotification在iOS 10及以后的版本中已经被完全弃用**,苹果推荐使用UserNotifications框架来处理本地通知。旧API在新的Swift版本和SDK中,类型系统对它的兼容性处理会出现问题,尤其是当你把UILocalNotification实例传给Reminder初始化器时,类型约束检查会触发这个报错。

另外,你的代码里还有两个潜在风险:

  • 强制解包name!,如果输入框为空会直接崩溃
  • 直接使用NSDate和Date的转换,在现代Swift中可以更简洁地处理

修复方案

我们需要迁移到UserNotifications框架,同时修复代码中的安全问题:

1. 导入新框架

在你的ViewController文件顶部添加:

import UserNotifications

2. 请求通知权限

在viewDidLoad()中添加权限请求(这是iOS 10+的必填步骤):

override func viewDidLoad() {
    super.viewDidLoad()
    // 请求通知权限
    UNUserNotificationCenter.current().requestAuthorization(options: [.alert, .sound]) { granted, error in
        if let error = error {
            print("请求通知权限失败:\(error.localizedDescription)")
        }
    }
}

3. 重写prepare(for:sender:)函数

替换成新的通知API,同时处理安全解包:

override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
    // 安全判断sender是否是保存按钮
    guard let tappedButton = sender as? UIButton, tappedButton === saveButton else {
        return
    }
    
    // 安全获取输入的提醒名称,为空则直接返回
    guard let reminderName = reminderTextField.text, !reminderName.isEmpty else {
        // 这里可以加个提示,比如弹框告诉用户输入不能为空
        return
    }
    
    // 处理时间,取整到分钟
    let selectedTime = timePicker.date
    let roundedTimeInterval = floor(selectedTime.timeIntervalSinceReferenceDate / 60) * 60
    let roundedTime = Date(timeIntervalSinceReferenceDate: roundedTimeInterval)
    
    // 创建通知内容
    let notificationContent = UNMutableNotificationContent()
    notificationContent.title = "Reminder"
    notificationContent.body = "Don't forget to \(reminderName)!"
    notificationContent.sound = UNNotificationSound.default
    
    // 创建时间触发条件
    let dateComponents = Calendar.current.dateComponents([.year, .month, .day, .hour, .minute], from: roundedTime)
    let trigger = UNCalendarNotificationTrigger(dateMatching: dateComponents, repeats: false)
    
    // 生成唯一的通知标识符(用于后续管理通知)
    let notificationID = UUID().uuidString
    // 创建通知请求
    let notificationRequest = UNNotificationRequest(identifier: notificationID, content: notificationContent, trigger: trigger)
    
    // 调度通知
    UNUserNotificationCenter.current().add(notificationRequest) { error in
        if let error = error {
            print("调度通知失败:\(error.localizedDescription)")
        }
    }
    
    // 更新Reminder实例(注意:如果你的Reminder类原来存储UILocalNotification,建议改成存储notificationID,因为UNNotificationRequest不可直接存储)
    reminder = Reminder(name: reminderName, time: roundedTime as NSDate, notificationIdentifier: notificationID)
}

4. 调整Reminder类(如果需要)

如果你的Reminder类原来的初始化器接收UILocalNotification类型的参数,建议修改为接收通知标识符(String类型),因为新的UNNotificationRequest是不可变的,且不适合直接存储:

class Reminder {
    let name: String
    let time: NSDate
    let notificationIdentifier: String
    
    init(name: String, time: NSDate, notificationIdentifier: String) {
        self.name = name
        self.time = time
        self.notificationIdentifier = notificationIdentifier
    }
}

为什么这能解决报错?

通过弃用旧的UILocalNotificationAPI,改用苹果推荐的UserNotifications框架,我们避开了旧API在新类型系统中的兼容性问题。同时,安全的可选绑定也消除了强制解包带来的崩溃风险,代码更健壮。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.29 09:17:28