2010-07-13 40 views
5

Tôi đã viết macro trong Objective-C để thực hiện một dàn diễn viên an toàn. Dưới đây là những gì nó trông giống như vậy cho đến nay:Macro đúc an toàn mục tiêu-C

#define SAFE_CAST(OBJECT, TYPE) ([OBJECT isKindOfClass:[TYPE class]] ? (TYPE *) OBJECT: nil) 

Điều này hoạt động thực sự tốt, nhưng nó sẽ là tốt đẹp nếu có một cách để lưu trữ OBJECT trong một biến để nó không được gọi hai lần. Ví dụ, bằng cách sử dụng vĩ mô như vậy:

NSString *str = SAFE_CAST([dictinary objectForKey:key], NSString); 

kết quả trong mã tương tự như sau khi vĩ mô được mở rộng:

NSString *str = ([[dictinary objectForKey:key] isKindOfClass:[NSString class]] ? (NSString *) [dictinary objectForKey:key]: nil); 

Tôi muốn cho nó đi làm thêm như thế này:

id obj = [dictionary objectForKey:key]; 
NSString *str = ([obj objectForKey:key] isKindOfClass[NSString class]] ? (NSString *) obj : nil); 

Cảm ơn.

+0

Tôi không thấy gì điểm của việc này là. Bạn đã nói rằng bạn muốn sử dụng nó để khử trùng plists, nhưng chắc chắn nếu bạn sử dụng này, bạn phải kiểm tra nếu đối tượng trả về là nil? Tại sao không chỉ kiểm tra nếu đối tượng làKindOfClass: expectedClass? – JeremyP

Trả lời

8

Bạn có thể dùng một phần mở rộng GCC kêu gọi tuyên bố statement expressions

#define SAFE_CAST(OBJECT, TYPE) ({ id obj=OBJECT;[obj isKindOfClass:[TYPE class]] ? (TYPE *) obj: nil; }) 

Điều đó nói rằng, tôi nghĩ rằng đó là nói chung là một cách tiếp cận xấu để có một tình huống mà bạn cần phải sử dụng SAFE_CAST rất nhiều. Không bao giờ đặt các đối tượng của các lớp khác nhau trong một mảng; không bao giờ sử dụng lại một thông điệp hành động (IBAction)someAction:(id)sender cho các đối tượng UI của các lớp khác nhau. Sau đó, bạn thường không cần sử dụng SAFE_CAST.

+1

Ngay bây giờ tôi đang sử dụng vĩ mô này khi đọc thông tin ra khỏi một plist. Tôi không đảm bảo nội dung của plist là hợp lệ. Nó giống như bất kỳ diễn viên nào khác; nó có thể bị lạm dụng, nhưng nó có sử dụng của nó. Nếu có một cách tốt hơn để làm điều này, bạn có thể vui lòng xây dựng? Theo trả lời của bạn, biểu thức tuyên bố trông thú vị. Chúng có thể được sử dụng với LLVM không? – LandonSchropp

+0

Có hoạt động với 'clang'. Đối với 'plist', tôi đồng ý với việc sử dụng' SAFE_CAST' nếu nó do người dùng cung cấp. Nhưng nếu không, tôi nghĩ tốt hơn là nên sử dụng 'NSAssert' trong khi phát triển, để chương trình bị treo cứng khi tôi chuẩn bị một plist không hợp lệ; bản phát hành ứng dụng của bạn không cần 'SAFE_CAST', vì bạn đảm bảo' plist' hợp lệ. – Yuji

+0

Hoạt động tuyệt vời. Cảm ơn. – LandonSchropp

0

Vì vậy, hãy viết như thế, chỉ cần bọc nó vào trong {} trong khi (0) < - và không chỉ trong dấu ngoặc đơn.

#define SAFE_CAST(OBJECT, TYPE, VAR) do { \ 
    id obj = OBJECT; \ 
    VAR = [obj isKindOfClass:[TYPE class]] ? (TYPE *) obj : nil; \ 
} while(0) 
+0

Tôi không thể làm điều này để biên dịch chính xác trong cách sử dụng tôi đã sử dụng ở trên. Các kết quả đầu ra của trình biên dịch: lỗi: biểu thức dự kiến ​​trước khi 'làm'. – LandonSchropp

+0

Err bạn nói đúng, xin lỗi. Đầu tiên có lỗi cú pháp sau nil, bị thiếu; và thứ hai, nó cần phải tự đứng vững. Có nghĩa là, hoặc là vượt qua trong một đối số mà chỉ định đầu ra của hoạt động ternary, hoặc làm điều đó một cách khác nhau. :) – jer

+0

Không phải lo lắng. Cảm ơn bạn đã trả lời. – LandonSchropp

4

Nếu bạn thực sự nghĩ rằng bạn phải làm điều này, bạn có thể sử dụng một chức năng:

#define SAFE_CAST(Object, Type) (Type *)cast_helper(Object, [Type class]) 
static id cast_helper(id x, Class c) { 
    return [x isKindOfClass:c] ? x : nil; 
} 
+0

Đó là một cách tiếp cận thú vị, nhưng macro chỉ có vẻ sạch hơn một chút. Tôi đang cố gắng tránh các chức năng toàn cầu trôi nổi xung quanh. Ngoài ra, bạn có thể vui lòng giải thích về những gì bạn có ý nghĩa của 'Nếu bạn thực sự nghĩ rằng bạn phải làm điều này'?Một số ngôn ngữ khác hỗ trợ truyền an toàn, bao gồm C# và C++. Tại sao tôi không nên sử dụng chúng? – LandonSchropp

+1

@helixed: tại sao bạn cho rằng một vĩ mô toàn cầu treo quanh là tốt hơn so với một chức năng toàn cầu treo xung quanh? – JeremyP

+0

@helixed: Đối với các phương pháp tiếp cận plist đã đề cập ở trên nó phù hợp, nó chỉ là tình huống mà những phôi năng động thực sự cần thiết là rất hiếm. Tôi không thấy vấn đề cụ thể với một chức năng toàn cầu mặc dù - tôi muốn sử dụng các chức năng hơn so với macro mà chỉ làm thẳng về phía trước xử lý văn bản. –

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