2011-02-05 9 views
6

Tôi vừa mới đi qua một số mã trong three20 trông như thế này:Tại sao sử dụng performSelector: withObject: withObject tại thời gian chạy nếu bạn biết cả bộ chọn và đối số của nó tại thời gian biên dịch?

SEL sel = @selector(textField:didAddCellAtIndex:); 
    if ([self.delegate respondsToSelector:sel]) { 
    [self.delegate performSelector:sel withObject:self withObject:(id)_cellViews.count-1]; 
    } 

On LLVM 2.0, điều này gây ra lỗi biên dịch:

error: arithmetic on pointer to interface 'id', which is not a constant size in non-fragile ABI

Tôi biết tại sao lỗi rằng đang xảy ra và tôi biết cách sửa nó. Tôi chỉ cần gọi phương thức trực tiếp, như vậy:

SEL sel = @selector(textField:didAddCellAtIndex:); 
    if ([self.delegate respondsToSelector:sel]) { 
    [self.delegate textField:self didAddCellAtIndex:(_cellViews.count - 1)]; 
    } 

Câu hỏi của tôi là, nếu bạn biết cả hai bộ chọn và lập luận của mình tại thời gian biên dịch, tại sao bạn sẽ cần phải sử dụng performSelector:withObject:withObject: khi chạy? Tôi không hiểu tại sao mã được viết theo cách này ngay từ đầu. Nếu bộ chọn và đối số được tự động chuyển vào phương thức, tôi có thể hiểu, nhưng chúng không, bộ chọn và đối số của nó được mã hóa cứng, (ngay cả khi chỉ mục thay đổi trong thời gian chạy, phương pháp của nó có được chỉ mục là khó được mã hóa.)

Nếu ai đó có thể giải thích cho tôi lý do chính đáng tại sao điều này là cần thiết, tôi sẽ rất biết ơn. Nếu không, tôi sẽ ở đây thay đổi tất cả các mã này.

Trả lời

10

Sau khi đào sâu hơn một chút, có vẻ như lớp TTPickerTextField mà mã này được tìm thấy là một phân lớp gián tiếp của số UITextField.

Vì vậy, nó là sự ủng hộ của heo trên tài sản ủy quyền UITextField, không tuân theo giao thức TTPickerTextFieldDelegate, nơi phương thức textField:didAddCellAtIndex: được khai báo.

Tôi đã đi đến kết luận rằng mã này chỉ là sự lười biếng. Không có lý do tại sao tài sản ủy quyền của UITextField phải được hỗ trợ bằng con heo đất, làm cho mã này dễ gây nhầm lẫn, dễ bị lỗi.

Cách tiếp cận của riêng tôi có thể là để lại UITextField của thuộc tính ủy nhiệm một mình và thêm thuộc tính của riêng tôi vào lớp con cụ thể của tôi xử lý các phương thức đại biểu cụ thể.

Chỉ cần làm rõ - 'giải pháp' tôi đã đề cập trong câu hỏi sửa lỗi trình biên dịch, nhưng tạo cảnh báo rằng phương thức không thể tìm thấy và sẽ được giả định trả về id. Đây là những gì mã ban đầu là 'giải quyết' nhưng chỉ làm việc trong GCC. Không còn với LLVM 2.0 nữa.

chỉnh sửa cuối, anh hứa:

giải pháp cuối cùng của tôi để chống lại sự lười biếng này và thoát khỏi cảnh báo và lỗi là một hack xấu xí:

[(id <TTPickerTextFieldDelegate>)self.delegate textField:self didAddCellAtIndex:(_cellViews.count - 1)]; 

Cast UITextField s đại biểu đến một id tuân đến TTPickerTextFieldDelegate và sau đó gọi trực tiếp phương thức.

Xin đừng lười biếng :(

+0

Ba20 không được chuyển giá trị số nguyên làm con trỏ. Naughty, Naughty. Cảm ơn bạn đã sửa chữa. – justice

5

Đó respondsToSelector/performSelector kết hợp là một thành ngữ cho các phương pháp đại biểu bắt buộc. Các đại biểu không được bảo đảm để có phương pháp xác định, do đó, một cuộc gọi trực tiếp đến nó sẽ gây ra một cảnh báo trình biên dịch.

gì trình biên dịch đã thực sự phàn nàn về trong trường hợp này:

[self.delegate performSelector:sel withObject:self withObject:(id)_cellViews.count-1]; 

error: arithmetic on pointer to interface 'id', which is not a constant size in non-fragile ABI 

là rủi ro con trỏ số học ... 'id' là một loại con trỏ, vì vậy:

(id)_cellViews.count-1 

nói với trình biên dịch nó sẽ trừ một từ một con trỏ thay vì một số nguyên .... mà có lẽ không phải là ý định của mã đó. Đối số withObject của performSelector phải là một con trỏ, nó không thể là một nguyên thủy. Bạn có thể giải quyết vấn đề này bằng cách gói _cellViews.count - 1 trong một NSNumber và mở nó trong phương thức ủy nhiệm.

[self.delegate performSelector:sel withObject:self withObject:[NSNumber numberWithInt:_cellViews.count-1]]; 
+0

Tôi biết lý do tại sao trình biên dịch phàn nàn ban đầu, và đó sẽ là một cách tiếp cận tốt hơn nhiều so với mã gốc, và có lẽ tốt hơn so với công việc của tôi xung quanh. Vấn đề duy nhất là loại mã này được đặt trong thư viện Three20 và thay đổi nó ở đây đòi hỏi phải thay đổi nó trong thư viện nơi nó được sử dụng. Điểm vẫn đứng đó là mã ban đầu được viết lờ mờ và không có tầm nhìn xa cho tương lai. – Jasarien

+0

Khi tôi không bận rộn với công cụ của riêng mình, tôi sẽ đóng góp thời gian của mình để khắc phục một số vấn đề này với Three20, nhưng ngay bây giờ, tôi có những thứ bugger trên đĩa của mình. – Jasarien