尝试使用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)
答案 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并在这种情况下忽略它。记录可能被标记为具有缩略图但由于某种原因无法加载,例如不兼容的图像类型。