2011-11-10 26 views
6

Điều này là tốt:Crash khi đúc CFArrayRef để NSArray

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

Điều này gây EXC_BAD_ACCESS:

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

Trả lời

8

Mảng được tạo dưới dạng NSArray s chỉ có thể chứa các phần tử hoạt động như đối tượng Objective-C.

Mảng được tạo thành CFArray s có thể chứa bất kỳ thứ gì, nếu bạn chuyển CFArrayCallBacks thích hợp đến CFArrayCreate.

CGWindowListCreate đang tạo một CFArray và điền vào những thứ không hoạt động như đối tượng, nhưng CGWindowListCreate đang sử dụng CFArrayCallbacks không quan tâm đến điều đó.

Khi bạn cố gắng in số CFArray này với thông số định dạng %@, NSLog gửi thông báo Mục tiêu-C -description tới mảng. CFArray xử lý việc này bằng cách gửi thông điệp Objective-C description tới từng phần tử của nó. Thật không may, các phần tử của nó không phải là các đối tượng và do đó không thể gửi các thông điệp Objective-C cho chúng. Vì vậy, vụ tai nạn.

Hãy thử điều này thay vì:

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

Chức năng CFCopyDescription sử dụng một trong những CFArrayCallbacks chức năng trên mỗi phần tử của mảng, thay vì cố gắng để gửi một thông báo Objective-C cho mỗi người. Gọi lại biết cách xử lý phần tử mảng, vì vậy nó hoạt động tốt. Tôi nhận được kết quả này trong chương trình thử nghiệm của tôi:

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! Bây giờ có ý nghĩa là tại sao nó hoạt động giống như một mảng C và một nửa giống như một đối tượng. Cảm ơn câu trả lời. –

1

Từ documentation trên NSArray:

NSArray là “cầu nối điện thoại miễn phí ”Với đối tác Core Foundation, Tham chiếu CFArray. Điều này có nghĩa là loại Core Foundation là có thể hoán đổi cho nhau trong các chức năng hoặc các cuộc gọi phương thức với đối tượng Foundation cầu nối, cung cấp cho bạn một loại khác. Vì vậy, trong một API mà bạn nhìn thấy một tham số NSArray *, bạn có thể vượt qua trong một CFArrayRef, và trong một API, nơi bạn nhìn thấy một tham số CFArrayRef , bạn có thể vượt qua trong một trường hợp NSArray. Sự sắp xếp này cũng áp dụng cho các lớp con cụ thể của NSArray.

Vì vậy, vấn đề phải bằng hai phương pháp được gọi. Một lần nữa, từ các tài liệu, CGWindowListCopyWindowInfo có giá trị trả về:

Một mảng của các loại CFDictionaryRef, mỗi trong số đó có chứa thông tin về một trong những cửa sổ trong user session hiện hành. Nếu không có cửa sổ khớp với tiêu chí mong muốn, hàm sẽ trả về mảng trống . Nếu bạn gọi hàm này từ bên ngoài bảo mật GUI phiên hoặc khi không có máy chủ cửa sổ nào đang chạy, hàm này trả về NULL.

CGWindowListCreate có giá trị trả về:

Một mảng các giá trị CGWindowID tương ứng với cửa sổ mong muốn. Nếu không có cửa sổ nào khớp với tiêu chí mong muốn, hàm sẽ trả về một mảng trống. Nếu bạn gọi hàm này từ bên ngoài phiên bảo mật GUI hoặc khi không có máy chủ cửa sổ nào đang chạy, hàm trả về NULL.

Khi bạn gọi NSLog(@"%@",array);, thông báo description được gửi đến từng đối tượng trong mảng. Nổi, BOOL và ints không trả lời thư này. Ví dụ, bạn sẽ nhận được một lỗi cho

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

nhưng lỗi sẽ biến mất nếu bạn sử dụng int gọi:

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

Đối với trường hợp của bạn, CGWindowListCreate được trả lại một mảng của CGWindowID giá trị, và những là các số nguyên không dấu 32 bit. Do đó, họ không trả lời %@, nhưng sẽ trả lời %u. Do đó sửa chữa là in mảng bằng tay sử dụng %u.

+0

OK, tôi đã cố gắng 'NSLog (@ "Mảng% ld", [(__bridge NSArray *) windowIDList đếm]); 'và nó sẽ trả về 14 và' CFArrayGetCount (windowIDList) 'và nó cũng trả về 14 vì vậy nó có vẻ là một mảng bình thường nhưng' NSLog (@ "Array% @", [(__bridge NSArray *) windowIDList objectAtIndex: 1]); 'vẫn bị treo. –

+1

Sau đó, vấn đề là 'CGWindowID' không trả lời' mô tả'. Nó có vẻ là một int không dấu 32 bit. Hãy thử 'NSLog (@" Mảng% u ", [(__bridge NSArray *) đối tượng windowIDListAtIndex: 0]);' – PengOne

+0

Nó hoạt động nhưng tôi không hiểu. –

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