2011-11-10 18 views
6

To jest w porządku:Błąd podczas odlewania CFArrayRef do NSArray

CFArrayRef windowList = CGWindowListCopyWindowInfo(kCGWindowListOptionOnScreenOnly, kCGNullWindowID); 
NSLog(@"%@", (__bridge NSArray *)windowList); 

Powoduje to EXC_BAD_ACCESS:

CFArrayRef windowIDList = CGWindowListCreate(kCGWindowListOptionOnScreenOnly, kCGNullWindowID); 
NSLog(@"Array %@", (__bridge NSArray*) windowIDList); 

Odpowiedz

8

Tablice utworzone jako NSArray mogą zawierać tylko elementy, które działają jak obiekty Objective-C.

Tablice utworzone jako CFArray s mogą zawierać dowolne treści, jeśli przekażemy odpowiednie CFArrayCallBacks do CFArrayCreate.

CGWindowListCreate jest stworzenie CFArray i wypełnienie go z rzeczy, które nie działają jak obiekty, ale CGWindowListCreate korzysta CFArrayCallbacks że nie dbam o to.

Podczas próby wydrukowania tego CFArray ze specyfikacją formatu %@, NSLog wysyła wiadomość -description Objective-C na tablicy. CFArray obsługuje to, wysyłając wiadomość Objective-C description do każdego z jej elementów. Niestety, jego elementy nie są obiektami, więc nie jest możliwe wysyłanie do nich wiadomości typu Objective-C. Tak więc katastrofa.

Spróbuj to zamiast:

CFStringRef description = CFCopyDescription(windowIDList); 
NSLog(@"Array %@", description); 
CFRelease(description); 

Funkcja CFCopyDescription wykorzystuje jedną z CFArrayCallbacks funkcji na każdym elemencie tablicy, zamiast próbować wysłać wiadomość Objective-C do każdej z nich. Callback wie, jak obsługiwać element tablicy, więc działa poprawnie. Mam to wyjście w moim programie testowym:

2011-11-10 18:50:23.888 test[15156:707] <CFArray 0x1001140c0 [0x7fff7fd24ea0]>{type = mutable-small, count = 19, values = (
    0 : <0x7d7> 
    1 : <0x2d> 
    2 : <0x20> 
    3 : <0x21> 
    4 : <0x1e> 
    5 : <0x9> 
    6 : <0x7a8> 
    7 : <0x2c> 
    8 : <0x2e> 
    9 : <0x743> 
    10 : <0x32> 
    11 : <0x85> 
    12 : <0x695> 
    13 : <0x62a> 
    14 : <0x62b> 
    15 : <0xa> 
    16 : <0x26> 
    17 : <0x18> 
    18 : <0x2> 
)} 
+0

Ah! Teraz ma to sens, dlaczego zachowywał się w połowie jak tablica C, a na pół jak obiekt. Dziękuję za odpowiedź. –

1

Z documentation na NSArray:

NSArray jest „bezpłatnego zmostkowany "Z odpowiednikiem Core Foundation, Reference CFArray. Oznacza to, że typ rdzenia rdzenia jest wymienny w wywołaniach funkcji lub metod za pomocą zmostkowanego obiektu fundacji , umożliwiając rzutowanie jednego typu na drugi. W związku z tym w interfejsie API, w którym jest wyświetlany parametr NSArray *, można przekazać wartość CFArrayRef w postaci , aw interfejsie API, w którym jest wyświetlany parametr CFArrayRef , można przekazać instancję NSArray. Ten układ również dotyczy twoich konkretnych podklas NSArray.

Problem musi być związany z wywoływaniem dwóch metod. Ponownie, z dokumentacji, CGWindowListCopyWindowInfo ma wartość powrotu:

Tablica typów CFDictionaryRef, z których każda zawiera informacje o jedno z okien w bieżącej sesji użytkownika. Jeśli nie ma okien spełniających wymagane kryteria, funkcja zwraca pustą tablicę . Jeśli wywołasz tę funkcję poza sesją zabezpieczeń GUI lub gdy nie jest uruchomiony żaden serwer okien, ta funkcja zwraca NULL.

i CGWindowListCreate ma wartość powrotną:

Tablica wartości CGWindowID odpowiadający mu okna. Jeśli nie ma okien pasujących do żądanych kryteriów, funkcja zwraca pustą tablicę. Jeśli wywołasz tę funkcję spoza sesji zabezpieczeń GUI lub gdy nie jest uruchomiony żaden serwer okien, ta funkcja zwraca wartość NULL.

Po wywołaniu NSLog(@"%@",array);, wiadomość description jest wysyłana do każdego obiektu w tablicy. Floats, BOOLs i int nie odpowiadają na tę wiadomość. Na przykład, otrzymasz błąd na

NSLog(@"Printing 2: %@",2); 

ale błąd nie zniknie, jeśli używasz int połączenia:

NSLog(@"Printing 2: %d",2); 

Twoim przypadku, CGWindowListCreate zwraca tablicę CGWindowID wartości, a te są 32-bitowymi liczbami całkowitymi bez znaku. Dlatego nie odpowiadają na %@, ale odpowiedzą na %u. Stąd poprawka polega na ręcznym drukowaniu tablicy przy użyciu %u.

+0

OK, starałem 'NSLog (@ "Array% ld", [(__bridge NSArray *) windowIDList liczyć]);' i zwraca 14 i 'CFArrayGetCount (windowIDList) 'i zwraca również 14, więc wydaje się być normalną tablicą, ale' NSLog (@ "Array% @", [(__bridge NSArray *) windowIDList objectAtIndex: 1]); 'nadal ulega awarii. –

+1

Problem polega na tym, że 'CGWindowID' nie odpowiada na' opis'. Wygląda na to, że jest to 32-bitowa unsigned int. Wypróbuj 'NSLog (@" Array% u ", [(__bridge NSArray *) windowIDList objectAtIndex: 0]);' – PengOne

+0

Działa, ale go nie rozumiem. –