2012-04-10 36 views
9

Tôi gặp sự cố lạ khi đăng ký ứng dụng iOS để nghe các thay đổi trong sổ địa chỉ của điện thoại. Phương thức chính xác được gọi khi có gì đó thay đổi trong sổ địa chỉ nhưng nó được gọi là 2 - 6 lần.ABAddressBookRegisterExternalChangeCallback được gọi nhiều lần

Khi các đối tượng được tạo ra (singleton, vì vậy chỉ có một đối tượng), tôi đăng ký thông báo với mã này:

ABAddressBookRegisterExternalChangeCallback(notificationAddressBook, addressBookChanged, (__bridge_retained void *)self); 

phương pháp

Các đó được gọi là vẻ bề ngoài như thế này:

void addressBookChanged(ABAddressBookRef ab, CFDictionaryRef info, void *context){ 
ABAddressBookRevert(ab); 

    NSLog(@"ADDRESSBOOK CHANGED"); 
    [phoneBookCopy updateCopy]; 
} 

Bất kỳ ý tưởng làm thế nào để giải quyết điều này?

+2

Tôi cũng gặp sự cố này. Mỗi khi tôi chuyển sang sổ địa chỉ iOS để thay đổi tên của một liên hệ và chuyển về ứng dụng của tôi, cuộc gọi lại được gọi là bốn lần - luôn luôn. Tôi đã thử thêm ngữ cảnh khi đăng ký và tôi thấy rằng ngữ cảnh của tôi được gửi cho tôi trong cả bốn cuộc gọi. Tôi đọc ở đây: http://stackoverflow.com/questions/7116956/gcd-and-callbacks-concurrency-issue rằng ai đó tuyên bố rằng đây là lỗi đã biết nhưng tôi chưa tìm thấy. Có ai có thêm thông tin về hành vi khó chịu này không? –

Trả lời

1

tôi đã cùng một vấn đề một lúc trước, và tôi đã phải giải quyết nó bằng cách tạo ra một NSTimer để xử lý các callbacks trùng lặp:

[self.changeTimer invalidate]; 
self.changeTimer = nil; 
self.changeTimer = [NSTimer scheduledTimerWithTimeInterval:3.0 
                  target:self 
                  selector:@selector(handleAdressBookExternalCallbackBackground) 
                  userInfo:nil 
                  repeats:NO]; 
+0

Tôi nghĩ bạn đang gọi phương thức: ABAddressBookRegisterExternalChangeCallback nhiều lần. –

+0

Xin lỗi, @Z S, tôi thấy tôi đã sai về điều này, bạn nói đúng, xin lỗi vì đã bỏ phiếu cho câu trả lời này !!!! – flypig

+0

Chỉ cần một cải tiến nhỏ, mã ZS sẽ chỉ chạy trình xử lý sau khi bộ hẹn giờ hết hạn, bạn có thể kiểm tra nếu changeTimer là không, nếu nó là xử lý thông báo và bắt đầu hẹn giờ. Bộ hẹn giờ nên gọi bộ chọn có đặt changeTimer = nil, vì vậy chúng tôi sẽ xử lý thông báo tiếp theo sau khi hết thời gian chờ – marmor

0

Tôi đã có một vấn đề tương tự. Cuộc gọi lại sẽ chỉ được gọi một lần lần đầu tiên, nhưng nếu tôi ra ngoài và thực hiện các thay đổi đối với sổ địa chỉ lần thứ hai, thì nó sẽ được gọi nhiều lần. Đối với tôi, vấn đề là phương pháp giữ ABAddressBookRegisterExternalChangeCallback đã được gọi trong phương thức applicationWillResignActive: của appDelegate.

Cách tôi đang sử dụng sổ địa chỉ là dành cho cài đặt đồng bộ hóa. Vấn đề là, tôi đã đăng ký cuộc gọi lại bên ngoài mỗi lần cài đặt đồng bộ hóa được lưu, thay vì chỉ khi cài đặt đồng bộ hóa đang được thay đổi.

Để minh họa, đây là đoạn code tôi đã gọi điện thoại trong appdelegate

- (void)saveSettings 
{ 
NSUserDefaults *syncSettingsData = [NSUserDefaults standardUserDefaults]; 
[syncSettingsData setObject:[NSNumber numberWithBool:self.isSyncingiPadContacts] forKey:SYNC_IPAD_CONTACTS_TURNED_ON]; 
[self setAddressBookChanged]; 
[syncSettingsData synchronize]; 
} 

- (void)setAddressBookChanged 
{ 
    if (self.isSyncingiPadContacts) 
    { 
     ABAddressBookRegisterExternalChangeCallback(self.addressBook, addressBookChanged, (__bridge void *)self); 
    } 
    else 
    { 
     ABAddressBookUnregisterExternalChangeCallback(self.addressBook, addressBookChanged, (__bridge void *) self); 
    } 
} 

tôi loại bỏ các cuộc gọi đến setAddressBookChanged trong phương pháp saveSettings, và chỉ có nó gọi khi addressbook đã được tạo ra (thiết lập lần đầu tiên lên) và bất cứ khi nào người dùng thay đổi cài đặt đồng bộ hóa.

Hy vọng điều này sẽ giúp ích cho bạn.

0

Giải pháp của tôi khá đơn giản và nó hoạt động, không chỉ cho điều này mà còn cho tất cả các cuộc gọi lặp lại (bao gồm các cuộc gọi lặp lại thông báo cục bộ): Tôi giữ một thuộc tính với thời gian cuộc gọi cuối cùng và kiểm tra khoảng thời gian. Hy vọng nó sẽ giúp, đối với tôi nó đã làm công việc.

AppDelegate * delegate = (__bridge AppDelegate *) context;

if (delegate.lastCall==nil) { 
    delegate.lastCall = [[NSDate alloc]init]; 
} 
else { 
    NSTimeInterval interval = [[NSDate date] timeIntervalSinceDate:delegate.lastCall]; 
    if (interval<20) { 
     return; 
    } 
    else { 
     delegate.lastCall = [[NSDate alloc]init]; 
    } 
} 
+0

logic tốt nhưng điều này có hoạt động hay không trong trường hợp đồng bộ hóa nhiều liên hệ trong nền từ google? –

3

thử điều này:

void addressBookChanged(ABAddressBookRef ab, CFDictionaryRef info, void *context){ 
ABAddressBookRevert(ab); 

    NSLog(@"ADDRESSBOOK CHANGED"); 
    [phoneBookCopy updateCopy]; 
    CFRelease(ab); 
} 

Nó được giúp cho tôi.

Các vấn đề liên quan