提取时应用崩溃>使用iOS 9 Contacts框架的800个联系人

时间:2016-05-04 18:25:14

标签: ios swift react-native

尝试使用iOS 9 Contacts框架获取设备上的所有统一联系人。尝试获取>时,应用会崩溃800个联系人。

我认为这是一个记忆问题。

以下是我的实施

@objc func searchContacts(searchText: String?, callback: (NSObject) -> ()) -> Void {

    let contactStore = CNContactStore()

    let keysToFetch = [ CNContactGivenNameKey, CNContactFamilyNameKey, CNContactImageDataAvailableKey, CNContactThumbnailImageDataKey ]

    do {

      var cNContacts = [CNContact]()

      let fetchRequest = CNContactFetchRequest(keysToFetch: keysToFetch)

      fetchRequest.sortOrder = CNContactSortOrder.GivenName

      try contactStore.enumerateContactsWithFetchRequest(fetchRequest) { (cNContact, pointer) -> Void in

        if !cNContact.givenName.isEmpty {  // Ignore any Contacts that don't have a Given Name. Garbage Contact.

          if searchText == nil {
            // Add all Contacts if no searchText is provided.
            cNContacts.append(cNContact)
          }
          else {
            // If the Contact contains the search string then add it.
            if self.contactContainsText( cNContact, searchText: searchText! ) {
              cNContacts.append(cNContact)
            }
          }
        }
      }

      var contacts = [NSDictionary]();

      for cNContact in cNContacts {
        contacts.append( convertCNContactToDictionary(cNContact) )
      }

      callback([NSNull(), contacts])
    }
    catch let error as NSError {
      NSLog("Problem getting unified Contacts")
      NSLog(error.localizedDescription)

      callback([error.localizedDescription, NSNull()])
    }

  }

这是字典转换器:

func convertCNContactToDictionary(cNContact: CNContact) -> NSDictionary {

        var contact = [String: AnyObject]()
        let phoneNumbers = NSMutableArray()

        contact["identifier"]         = cNContact.identifier
        contact["givenName"]          = cNContact.givenName
        contact["familyName"]         = cNContact.familyName
        contact["imageDataAvailable"] = cNContact.imageDataAvailable

        if (cNContact.imageDataAvailable) {
          let thumbnailImageDataAsBase64String = cNContact.thumbnailImageData!.base64EncodedStringWithOptions([])
          contact["thumbnailImageData"] = thumbnailImageDataAsBase64String

    //      let imageDataAsBase64String = cNContact.imageData!.base64EncodedStringWithOptions([])
    //      contact["imageData"] = imageDataAsBase64String
        }

        if (cNContact.isKeyAvailable(CNContactPhoneNumbersKey)) {
          for number in cNContact.phoneNumbers {
            var numbers = [String: AnyObject]()
            let phoneNumber = (number.value as! CNPhoneNumber).valueForKey("digits") as! String
            let countryCode = (number.value as! CNPhoneNumber).valueForKey("countryCode") as? String
            let label = CNLabeledValue.localizedStringForLabel(number.label)
            numbers["number"] = phoneNumber
            numbers["countryCode"] = countryCode
            numbers["label"] = label
            phoneNumbers.addObject(numbers)
          }
          contact["phoneNumbers"] = phoneNumbers
        }

        let contactAsNSDictionary = contact as NSDictionary

        return contactAsNSDictionary;
      }

修改

所以我在我的模拟器中添加了一堆联系人,可以重现崩溃。

这是stacktrace:

 libswiftCore.dylib`function signature specialization <Arg[0] = Exploded, Arg[1] = Exploded, Arg[2] = Dead, Arg[3] = Dead> of Swift._fatalErrorMessage (Swift.StaticString, Swift.StaticString, Swift.StaticString, Swift.UInt) -> ():
    0x107e73180 <+0>:   pushq  %rbp
    0x107e73181 <+1>:   movq   %rsp, %rbp
    0x107e73184 <+4>:   pushq  %rbx
    0x107e73185 <+5>:   pushq  %rax
    0x107e73186 <+6>:   movq   %rcx, %r10
    0x107e73189 <+9>:   testb  $0x1, %dl
    0x107e7318c <+12>:  jne    0x107e731aa               ; <+42>
    0x107e7318e <+14>:  testq  %rsi, %rsi
    0x107e73191 <+17>:  js     0x107e731f9               ; <+121>
    0x107e73193 <+19>:  addq   %rdi, %rsi
    0x107e73196 <+22>:  movzbl %r9b, %eax
    0x107e7319a <+26>:  movq   %r10, %rdx
    0x107e7319d <+29>:  movq   %r8, %rcx
    0x107e731a0 <+32>:  movl   %eax, %r8d
    0x107e731a3 <+35>:  callq  0x107eccea0               ; function signature specialization <Arg[0] = Exploded, Arg[1] = Exploded> of Swift.(_fatalErrorMessage (Swift.StaticString, Swift.StaticString, Swift.StaticString, Swift.UInt) -> ()).(closure #2)
->  0x107e731a8 <+40>:  ud2    
    0x107e731aa <+42>:  movq   $0x0, -0x10(%rbp)
    0x107e731b2 <+50>:  movl   %edi, %eax
    0x107e731b4 <+52>:  cmpq   %rax, %rdi
    0x107e731b7 <+55>:  jne    0x107e73303               ; <+387>
    0x107e731bd <+61>:  cmpl   $0xd7ff, %edi             ; imm = 0xD7FF 
    0x107e731c3 <+67>:  ja     0x107e73222               ; <+162>
    0x107e731c5 <+69>:  xorl   %esi, %esi
    0x107e731c7 <+71>:  cmpl   $0x80, %edi
    0x107e731cd <+77>:  movl   $0x0, %r11d
    0x107e731d3 <+83>:  jb     0x107e732f6               ; <+374>
    0x107e731d9 <+89>:  movl   %edi, %r11d
    0x107e731dc <+92>:  shrl   $0x6, %r11d
    0x107e731e0 <+96>:  cmpl   $0x800, %edi              ; imm = 0x800 
    0x107e731e6 <+102>: jae    0x107e7329b               ; <+283>
    0x107e731ec <+108>: orb    $-0x40, %r11b
    0x107e731f0 <+112>: xorl   %esi, %esi
    0x107e731f2 <+114>: xorl   %ebx, %ebx
    0x107e731f4 <+116>: jmp    0x107e732c6               ; <+326>
    0x107e731f9 <+121>: leaq   0xd3d92(%rip), %rdi       ; "fatal error"
    0x107e73200 <+128>: leaq   0xd3f89(%rip), %rcx       ; "UnsafeBufferPointer with negative count"
    0x107e73207 <+135>: movl   $0xb, %esi
    0x107e7320c <+140>: movl   $0x2, %edx
    0x107e73211 <+145>: movl   $0x27, %r8d
    0x107e73217 <+151>: movl   $0x2, %r9d
    0x107e7321d <+157>: callq  0x107e73180               ; <+0>
    0x107e73222 <+162>: cmpl   $0xe000, %edi             ; imm = 0xE000 
    0x107e73228 <+168>: jb     0x107e73272               ; <+242>
    0x107e7322a <+170>: cmpl   $0x110000, %edi           ; imm = 0x110000 
    0x107e73230 <+176>: jae    0x107e73352               ; <+466>
    0x107e73236 <+182>: movl   %edi, %r11d
    0x107e73239 <+185>: shrl   $0x6, %r11d
    0x107e7323d <+189>: movl   %edi, %eax
    0x107e7323f <+191>: shrl   $0xc, %eax
    0x107e73242 <+194>: cmpl   $0xffff, %edi             ; imm = 0xFFFF 
    0x107e73248 <+200>: jbe    0x107e732a0               ; <+288>
    0x107e7324a <+202>: movl   %edi, %ecx
    0x107e7324c <+204>: shrl   $0x12, %ecx
    0x107e7324f <+207>: orl    $0xf0, %ecx
    0x107e73255 <+213>: movzbl %cl, %edx
    0x107e73258 <+216>: cmpl   %edx, %ecx
    0x107e7325a <+218>: jne    0x107e73303               ; <+387>
    0x107e73260 <+224>: andb   $0x3f, %al
    0x107e73262 <+226>: orb    $-0x80, %al
    0x107e73264 <+228>: movzbl %cl, %edx
    0x107e73267 <+231>: movq   %rdx, -0x10(%rbp)
    0x107e7326b <+235>: movl   $0x1, %esi
    0x107e73270 <+240>: jmp    0x107e732a6               ; <+294>
    0x107e73272 <+242>: leaq   0xd3d19(%rip), %rdi       ; "fatal error"
    0x107e73279 <+249>: leaq   0xd4a80(%rip), %rcx       ; "high- and low-surrogate code points are not valid Unicode scalar values"
    0x107e73280 <+256>: movl   $0xb, %esi
    0x107e73285 <+261>: movl   $0x2, %edx
    0x107e7328a <+266>: movl   $0x47, %r8d
    0x107e73290 <+272>: movl   $0x2, %r9d
    0x107e73296 <+278>: callq  0x107e73180               ; <+0>
    0x107e7329b <+283>: movl   %edi, %eax
    0x107e7329d <+285>: shrl   $0xc, %eax
    0x107e732a0 <+288>: orb    $-0x20, %al
    0x107e732a2 <+290>: xorl   %esi, %esi
    0x107e732a4 <+292>: xorl   %edx, %edx
    0x107e732a6 <+294>: leaq   (,%rsi,8), %rcx
    0x107e732ae <+302>: andb   $0x3f, %r11b
    0x107e732b2 <+306>: orb    $-0x80, %r11b
    0x107e732b6 <+310>: movzbl %al, %ebx
    0x107e732b9 <+313>: shlq   %cl, %rbx
    0x107e732bc <+316>: orq    %rdx, %rbx
    0x107e732bf <+319>: movq   %rbx, -0x10(%rbp)
    0x107e732c3 <+323>: incq   %rsi
    0x107e732c6 <+326>: movl   $0x8, %ecx
    0x107e732cb <+331>: movq   %rsi, %rax
    0x107e732ce <+334>: mulq   %rcx
    0x107e732d1 <+337>: jo     0x107e73303               ; <+387>
    0x107e732d3 <+339>: cmpq   $0x3f, %rax
    0x107e732d7 <+343>: ja     0x107e73329               ; <+425>
    0x107e732d9 <+345>: andl   $0x3f, %edi
    0x107e732dc <+348>: orq    $0x80, %rdi
    0x107e732e3 <+355>: movzbl %r11b, %r11d
    0x107e732e7 <+359>: movb   %al, %cl
    0x107e732e9 <+361>: shlq   %cl, %r11
    0x107e732ec <+364>: orq    %rbx, %r11
    0x107e732ef <+367>: movq   %r11, -0x10(%rbp)
    0x107e732f3 <+371>: incq   %rsi
    0x107e732f6 <+374>: movl   $0x8, %ecx
    0x107e732fb <+379>: movq   %rsi, %rax
    0x107e732fe <+382>: mulq   %rcx
    0x107e73301 <+385>: jno    0x107e73305               ; <+389>
    0x107e73303 <+387>: ud2    
    0x107e73305 <+389>: cmpq   $0x40, %rax
    0x107e73309 <+393>: jae    0x107e73329               ; <+425>
    0x107e7330b <+395>: movzbl %dil, %edx
    0x107e7330f <+399>: movb   %al, %cl
    0x107e73311 <+401>: shlq   %cl, %rdx
    0x107e73314 <+404>: orq    %r11, %rdx
    0x107e73317 <+407>: movq   %rdx, -0x10(%rbp)
    0x107e7331b <+411>: leaq   -0x10(%rbp), %rdi
    0x107e7331f <+415>: leaq   0x1(%rsi,%rdi), %rsi
    0x107e73324 <+420>: jmp    0x107e73196               ; <+22>
    0x107e73329 <+425>: leaq   0xd3c62(%rip), %rdi       ; "fatal error"
    0x107e73330 <+432>: leaq   0xd3df9(%rip), %rcx       ; "shift amount is larger than type size in bits"
    0x107e73337 <+439>: movl   $0xb, %esi
    0x107e7333c <+444>: movl   $0x2, %edx
    0x107e73341 <+449>: movl   $0x2d, %r8d
    0x107e73347 <+455>: movl   $0x2, %r9d
    0x107e7334d <+461>: callq  0x107e73180               ; <+0>
    0x107e73352 <+466>: leaq   0xd3c39(%rip), %rdi       ; "fatal error"
    0x107e73359 <+473>: leaq   0xd49f0(%rip), %rcx       ; "value is outside of Unicode codespace"
    0x107e73360 <+480>: movl   $0xb, %esi
    0x107e73365 <+485>: movl   $0x2, %edx
    0x107e7336a <+490>: movl   $0x25, %r8d
    0x107e73370 <+496>: movl   $0x2, %r9d
    0x107e73376 <+502>: callq  0x107e73180               ; <+0>
    0x107e7337b <+507>: nopl   (%rax,%rax)

我不知道为什么会这样。 enter image description here

2 个答案:

答案 0 :(得分:3)

我尝试了您的代码,并且能够快速加载超过1200条记录并且没有任何问题。我一开始并没有真正修改你的代码,所以我不确定你为什么会崩溃。我确实有一些想法。首先,为什么不在CNContactFetchRequest上使用谓词字段?我认为这会让事情变得更快,你会得到一个子集。我意识到这可能不适合您的需求,因为您可能希望搜索更多名称字段。但是,这就是我尝试的重构的样子:

func searchContacts(searchText: String?, callback: (NSArray) -> ()) -> Void {
    let contactStore = CNContactStore()

    let keysToFetch = [ CNContactGivenNameKey, CNContactFamilyNameKey, CNContactImageDataAvailableKey, CNContactThumbnailImageDataKey ]

    do {
        var contacts = [NSDictionary]();

        let fetchRequest = CNContactFetchRequest(keysToFetch: keysToFetch)

        fetchRequest.sortOrder = CNContactSortOrder.GivenName

        // Create a predicate here based on the search text passed in
        fetchRequest.predicate = CNContact.predicateForContactsMatchingName(searchText!)

        try contactStore.enumerateContactsWithFetchRequest(fetchRequest) { (cNContact, pointer) -> Void in
            // Just append the contact because we won't have any that don't
            // contain the search string since we used a predicate.

            // The .dictionary property is from our extension and it converts
            // the CNContact object to a dictionary
            contacts.append(cNContact.dictionary)
        }

        callback([NSNull(), contacts])
    }
    catch let error as NSError {
        NSLog("Problem getting unified Contacts")
        NSLog(error.localizedDescription)

        callback([error.localizedDescription, NSNull()])
    }

}

请注意,我在CNContact上创建了一个扩展程序,以将联系人转换为字典。除自我(CNContact)上下文外,该代码与您的转换代码相同:

extension CNContact {
    var dictionary : NSDictionary {

        var contact = [String: AnyObject]()
        let phoneNumbers = NSMutableArray()

        contact["identifier"]         = self.identifier
        contact["givenName"]          = self.givenName
        contact["familyName"]         = self.familyName
        contact["imageDataAvailable"] = self.imageDataAvailable

        if (self.imageDataAvailable) {
            let thumbnailImageDataAsBase64String = self.thumbnailImageData!.base64EncodedStringWithOptions([])
            contact["thumbnailImageData"] = thumbnailImageDataAsBase64String                
        }

        if (self.isKeyAvailable(CNContactPhoneNumbersKey)) {
            for number in self.phoneNumbers {
                var numbers = [String: AnyObject]()
                let phoneNumber = (number.value as! CNPhoneNumber).valueForKey("digits") as! String
                let countryCode = (number.value as! CNPhoneNumber).valueForKey("countryCode") as? String
                let label = CNLabeledValue.localizedStringForLabel(number.label)
                numbers["number"] = phoneNumber
                numbers["countryCode"] = countryCode
                numbers["label"] = label
                phoneNumbers.addObject(numbers)
            }
            contact["phoneNumbers"] = phoneNumbers
        }

        let contactAsNSDictionary = contact as NSDictionary

        return contactAsNSDictionary;
    }
}

出于好奇,我将您的代码扔进了一个锅炉板主要详细信息表视图项目,该项目搜索联系人并应用我的重构。你可以从这里抓住它:man page。 (示例项目中的搜索栏要求您在尝试搜索之前键入至少3个字母,顺便说一句。)

答案 1 :(得分:0)

我会检查thumbnailImageData是否为nil并在这种情况下忽略它。记录可能被标记为具有缩略图但由于某种原因无法加载,例如不兼容的图像类型。