Swift开发提醒应用时出现Argument type 'Any'预期为类或类约束类型实例错误该如何解决?
问题场景
我正在开发一款提醒应用,在编写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

