2014-12-31 2 views
1

ABAddressBook을 사용하는 사람들의 이름과 이메일에 액세스 할 수있는 몇 가지 기능이 있습니다. 이 기능은 이름과 전자 메일을 connections 배열에 추가합니다. 내가 직면 한 문제는 사용자가 처음으로 주소록에 액세스하라는 메시지를 표시하고 예를 누를 때 배열이로드되지만 테이블 뷰가 업데이트되지 않는다는 것입니다.ABAddressBook (Swift)에서 배열로 UITableView로드하기

두 번째로 앱이로드되고 (이미 '예'로 설정 되었기 때문에 질문을받지 않는 경우) 배열이로드되고 tableview가 업데이트됩니다.

왜 이런지 알 수 없습니다. 나는 그것이 두 번째 시도에서 작동하기 때문에 reloadData()과 관련이 있다고 생각하지 않습니다.

제 생각에는 코드의 논리에 대해 잘못된 것이 있습니다 만, 알아낼 수 없습니다.

코드 :

func getAddressBookNames() { 
     let authorizationStatus = ABAddressBookGetAuthorizationStatus() 
     if (authorizationStatus == ABAuthorizationStatus.NotDetermined) { 
      var emptyDictionary: CFDictionaryRef? 
      var addressBook = !(ABAddressBookCreateWithOptions(emptyDictionary, nil) != nil) 
      ABAddressBookRequestAccessWithCompletion(addressBook,{success, error in 
       if success { 
        self.processContactNames(); 
       } 
       else { 
        println("Unable to request access") 
       } 
      }) 
     } else if (authorizationStatus == ABAuthorizationStatus.Denied || authorizationStatus == ABAuthorizationStatus.Restricted) { 
      println("access denied") 
     } else if (authorizationStatus == ABAuthorizationStatus.Authorized) { 
      println("access granted") 
      processContactNames() 
     } 
    } 

    func processContactNames() 
    { 
     var errorRef: Unmanaged<CFError>? 
     var addressBook: ABAddressBookRef? = extractABAddressBookRef(ABAddressBookCreateWithOptions(nil, &errorRef)) 
     println(addressBook) 
     var contactList: NSArray = ABAddressBookCopyArrayOfAllPeople(addressBook).takeRetainedValue() 
     println("records in the array \(contactList.count)") 

     for record:ABRecordRef in contactList { 
      processAddressbookRecord(record) 
     } 
    } 

    func processAddressbookRecord(addressBookRecord: ABRecordRef) { 
     var contactName: String = ABRecordCopyCompositeName(addressBookRecord).takeRetainedValue() as NSString 
     connections.append("\(contactName) is an aquaintance") 
     connectionDetails.append("Learned from Contacts") 
     connectionCounter.text = "\(connections.count) Connections" 
     processEmail(addressBookRecord, contactNameForEmail: contactName) 
    } 

    func processEmail(addressBookRecord: ABRecordRef, contactNameForEmail: String) { 
     let emailArray:ABMultiValueRef = extractABEmailRef(ABRecordCopyValue(addressBookRecord, kABPersonEmailProperty))! 
     for (var j = 0; j < ABMultiValueGetCount(emailArray); ++j) { 
      var emailAdd = ABMultiValueCopyValueAtIndex(emailArray, j) 
      var emailString = extractABEmailAddress(emailAdd) 
      connections.append("\(contactNameForEmail)'s email is \(emailString!)") 
      connectionDetails.append("Learned from Contacts") 
      connectionCounter.text = "\(connections.count) Connections" 
     } 
    } 

    func extractABAddressBookRef(abRef: Unmanaged<ABAddressBookRef>!) -> ABAddressBookRef? { 
     if let ab = abRef { 
      return Unmanaged<NSObject>.fromOpaque(ab.toOpaque()).takeUnretainedValue() 
     } 
     return nil 
    } 

    func extractABEmailRef (abEmailRef: Unmanaged<ABMultiValueRef>!) -> ABMultiValueRef? { 
     if let ab = abEmailRef { 
      return Unmanaged<NSObject>.fromOpaque(ab.toOpaque()).takeUnretainedValue() 
     } 
     return nil 
    } 

    func extractABEmailAddress (abEmailAddress: Unmanaged<AnyObject>!) -> String? { 
     if let ab = abEmailAddress { 
      return Unmanaged.fromOpaque(abEmailAddress.toOpaque()).takeUnretainedValue() as CFStringRef 
     } 
     return nil 
    } 

답변

1

그것은 않습니다는 reloadData() 함께 할 수 있습니다. 그것은 당신이 그것을 부르지 않는다는 사실과 관련이 있습니다. 불러라!

중요한 점은 ABAddressBookRequestAccessWithCompletion은 비동기입니다. 따라서 완성 처리기가 호출 될 때까지 테이블 뷰는 데이터가없는 시점에 데이터를 이미로드했습니다. 따라서 테이블은 비어 있습니다. 까지 테이블보기에 내용이 변경되었음을 알리기 위해 reloadData()으로 전화하십시오. 이번에는 테이블보기에서 데이터가 있음을 발견하고이를 표시합니다.

그러나 꼬임이 있습니다. 완료 처리기가 비동기적일뿐만 아니라 스레드도 처리됩니다. 여기에있는 문서에주의를 기울이십시오.

완료 핸들러는 임의의 대기열에서 호출됩니다. 응용 프로그램에서 응용 프로그램 전체에서 주소록을 사용하는 경우 해당 주소록의 모든 사용이 올바른 대기열에 안전하게 작동하도록 단일 대기열에 전달되도록해야합니다.

당신은 그렇게하지 않습니다. 완료 처리기에서 즉시 주 스레드로 이동해야합니다. 이제 모든 것이 좋은 상태로 진행됩니다. 결국 reloadData()으로 전화하면 모든 것이 잘됩니다.

+0

내가 생각할 수있는 모든 가능한 포인트 이후에 reloadData()를 호출 해 보았습니다! 난 그냥 '성공 processContactNames()'후 다시 호출 해 보았습니다. 아직도 작동하지 않았다. 내가 어디에서 불러야한다고 생각하니? –

+0

죄송합니다. 스레드 문제가 있습니다. 내 대답을 업데이트 할게. – matt

+0

완벽! 고마워요. –