【问题标题】:Workaround for EKParcipant URL accessing crash?EKParcipant URL 访问崩溃的解决方法?
【发布时间】:2016-11-25 11:35:26
【问题描述】:

我的一些用户已收到日志,指出这行代码中出现EXC_BREAKPOINT (SIGTRAP) 错误。我一直在努力使其安全,但 EKParticipant 的所有属性都是非可选的,因此与 nil 相比只会给我一个警告,说它永远是正确的。如果这里有什么东西是零,我应该如何处理它?

错误线

let participantEmail : String? = participant.url.absoluteString.lowercased().replacingOccurrences(of: "mailto:", with: "")

Apple 错误说明

跟踪陷阱 [EXC_BREAKPOINT // SIGTRAP]

类似于异常退出,此异常旨在提供 附加的调试器有机会在特定的地方中断进程 指向它的执行。您可以自己触发此异常 使用 __builtin_trap() 函数的代码。如果没有附加调试器, 进程终止并生成崩溃报告。低等级 库(例如 libdispatch)将在遇到 致命错误。有关该错误的其他信息,请参见 崩溃报告的附加诊断信息部分,或 在设备的控制台中。 Swift 代码将终止并出现此异常 如果在运行时遇到意外情况,请键入,例如: 具有 nil 值的非可选类型 强制类型转换失败 查看 Backtraces 以确定遇到意外情况的位置。额外的 信息也可能已记录到设备的控制台。你 应该修改崩溃位置的代码以优雅地处理 运行时失败。例如,使用可选绑定而不是 强制解开一个可选项。”

完整方法

    /**
Parses participants for a given event.
 Goes through the EKEvents attendees array to build Attendee objects used to model a participant.

 - parameter event: The calendar event we'll be finding the participants for.
 - returns: An array of Attendee objects with the participants name, email, required/optional status and whether they've accepted their invitation to the event.
 */
private static func parseParticipantsIn(event: EKEvent) -> [Attendee] {
var participants = [Attendee]()

if let attendees = event.attendees, event.attendees?.isEmpty == false {
    for participant in attendees {
        let participantName : String? = parse(EKParticipantName: participant)
            let participantEmail : String? = participant.url.absoluteString.lowercased().replacingOccurrences(of: "mailto:", with: "")

            let isRequiredParticipant : Bool = participant.participantRole == EKParticipantRole.required
            let hasAccepted : Bool = participant.participantStatus == EKParticipantStatus.accepted

             guard (participantName != nil && participantEmail !=  nil)
                else
            {
                log.error("Participant could not be parsed")
                continue
            }
            let attendee = Attendee(name: participantName!, email: participantEmail!, required: isRequiredParticipant, hasAccepted: hasAccepted)
            participants.append(attendee)
        }
    }
    return participants
}

【问题讨论】:

  • 这是关于NRURLabsoluteString 返回可选的String 吗? let participantEmail : String? = url.absoluteString?.lowercased().replacingOccurrences(of: "mailto:", with: "")
  • @SunilChauhan 我已经尝试过了,但我收到一个错误消息,提示 cannot use optional chaining on non optional value of 'String'
  • 那么应该有一些和swift版本有关的东西。你在哪个版本? 2.2 我猜。
  • @SunilChauhan 3.1
  • 奇怪。我的是 swift 3.0,除非我把 ?absoluteString 放在一起,否则无法编译。

标签: swift swift3


【解决方案1】:

这似乎是EKParticipant.url 属性的问题。如果您的参与者中包含以下电子邮件字段,则任何尝试访问 EKParticipant.url 都会导致崩溃。

"Bill Gates" <billgates@google.com>

我猜引号会过早地结束字符串。从EKParticipant.description 访问时很好,所以我打算从那里解析它。

【讨论】:

  • 请也报告一个错误。
【解决方案2】:

这是一个荒谬的问题,德科准确地指出了这一点。不过,我使用了一种不同的方法来解决它:由于我已经在混合代码库(obj-c 和 Swift)中工作,因此我在我的一个 obj-c 类上创建了一个类方法,该类方法接受一个 EKParticipant 并返回它的URL 作为字符串。然后,在 Swift 中,我调用该类方法来获取 URL,而不是直接访问属性(并崩溃)。这很 hacky,但总比崩溃好,让我免于解析描述。

【讨论】:

    【解决方案3】:

    这是一个相当老的问题,但我自己也遇到了这个问题。我的解决方案是回退到 ObjC 以解决它。

    只需将此 ObjC 函数添加到 swift 桥接头文件中,您就可以在 swift 中使用它们。

    static inline BOOL
    participantHasNonNilURL (EKParticipant* _Nonnull  participant) {
        return participant.URL != nil;
    }
    
    static inline NSURL* _Nullable
    participantURL(EKParticipant* _Nonnull  participant) {
        if (participant.URL != nil) {
            return participant.URL;
        }else {
            return nil;
        }
    }
    

    使用示例:

    extension EKParticipant {
        var optionalURL: URL? {
            return participantURL(self)
        }
    
        var hasURL: Bool {
            return participantHasNonNilURL(self)
        }
    }
    

    【讨论】:

      【解决方案4】:

      这在 macOS 11.2 上仍然是一个问题...我已将 reported 发送给 Apple。我鼓励其他遇到此问题的人也这样做。

      唯一对我有用的仅限 Swift 的解决方法是:

      extension EKParticipant {
          public var safeURL: URL? {
              perform(#selector(getter: EKParticipant.url))?.takeUnretainedValue() as? NSURL? as? URL
          }
      }
      

      【讨论】:

        【解决方案5】:

        验证添加不正确,请查看以下关于如何使用防护的回复。

        if let attendees = event.attendees, event.attendees?.isEmpty == false {
            for participant in attendees {
                guard let participantName : String? = parse(EKParticipantName: participant) else{ 
                      log.error("error in participant name")
                      return
                  }
                guard let participantEmail : String? = participant.url.absoluteString.lowercased().replacingOccurrences(of: "mailto:", with: "") else{ 
                      log.error("error in participant email")
                      return
                  }
        
               let isRequiredParticipant : Bool = participant.participantRole == EKParticipantRole.required
               let hasAccepted : Bool = participant.participantStatus == EKParticipantStatus.accepted
        
               /* guard validation is not required here */
               if (participantName != nil && participantEmail !=  nil){
                    let attendee = Attendee(name: participantName!, email: participantEmail!, required: isRequiredParticipant, hasAccepted: hasAccepted)
                    participants.append(attendee)
               }
            }
        }
        return participants
        

        【讨论】:

        • 我会试一试,谢谢。我在警卫语句的行上确实有一个警告,说“明确指定类型'字符串?”为初始化程序添加了额外的可选级别,使可选检查始终成功。这是什么意思?
        猜你喜欢
        • 2012-08-16
        • 2020-06-15
        • 1970-01-01
        • 1970-01-01
        • 2018-10-23
        • 1970-01-01
        • 1970-01-01
        • 2012-02-13
        • 1970-01-01
        相关资源
        最近更新 更多