2009-03-14 26 views
26

Tôi có UIViewController tùy chỉnh và UIView tùy chỉnh. Tôi muốn ghi đè thuộc tính viewcontroller.view để trả về MyCustomUIView.Làm cách nào để ghi đè thuộc tính "chế độ xem" trong UIViewController?

Ngay bây giờ tôi có:

@interface MyViewController : UIViewController {  
    IBOutlet MyView* view; 
} 

@property (nonatomic, retain) IBOutlet MyView* view; 

này biên dịch nhưng tôi nhận được một cảnh báo: bất động sản 'xem' loại không phù hợp siêu đẳng 'UIViewController' loại bất động sản.

Làm cách nào để giảm bớt cảnh báo này?

+2

Tôi nghĩ rằng bạn nên sử dụng thay vì '@ dynamic'. Vui lòng đọc [câu hỏi này] (http://stackoverflow.com/questions/1160498/synthesize-vs-dynamic-what-are-the-differences), câu trả lời có thật sự hữu ích cho tôi :) – Ondrej

+3

Có bài viết rất hay được gọi là [Ghi đè thuộc tính Chế độ xem của UIViewController, Hoàn thành ngay] (http://travisjeffery.com/b/2012/12/overriding-uiviewcontrollers-view-property-done-right/). – lambdas

Trả lời

18

Câu trả lời ngắn gọn là bạn không trả lời. Lý do là các thuộc tính thực sự chỉ là các phương thức và nếu bạn cố thay đổi kiểu trả về, bạn sẽ nhận được điều này:

  • (UIView *) xem;
  • (Chế độ xem MyView *);

Mục tiêu-C thực hiện không cho phép trả về hiệp phương sai trả về.

Những gì bạn có thể làm là thêm thuộc tính mới "myView" và làm cho nó chỉ đơn giản là định kiểu thuộc tính "chế độ xem". Điều này sẽ làm giảm bớt các lỗi trong suốt mã của bạn. Chỉ cần gán phân lớp view của bạn cho thuộc tính view, và mọi thứ sẽ hoạt động tốt.

+0

+1 để cho chính xác các phần còn thiếu từ những gì tôi trả lời :) –

4

Thuộc tính/phương thức chế độ xem của UIViewController sẽ tự động trả lại chế độ xem của bạn. Tôi nghĩ bạn sẽ chỉ cần đưa kết quả vào MyView (hoặc chỉ sử dụng loại id):

MyView *myView = (MyView*)controller.view; 
id myView = controller.view; 

Tôi nghĩ rằng mã bạn đã đăng ở trên sẽ gây rắc rối cho bạn. Bạn có thể không muốn tự tạo thành viên xem (vì sau đó bộ điều khiển sẽ lưu trữ 2 chế độ xem và có thể không sử dụng đúng nội dung) hoặc ghi đè thuộc tính chế độ xem (vì UIViewController có cách xử lý đặc biệt cho nó.) (Xem this question) để biết thêm thông tin về trường hợp sau.)

4

Xin lỗi, nhưng câu trả lời ngắn của bạn là sai.

Việc triển khai chính xác điều này sẽ là thêm @property vào tệp tiêu đề có loại trả về của bạn. Sau đó, thay vì @synthesize bạn thêm getter và setter bằng tay và trả về một kiểu dàn diễn viên từ [siêu view]

ví dụ lớp học của tôi là một PlayerViewController

PlayerViewController.h

@property (strong, nonatomic) IBOutlet PlayerView *view; 

PlayerViewController. m

- (PlayerView *)view{ 
    return (PlayerView*)[super view]; 
} 
- (void)setView:(PlayerView *)view{ 
    [super setView:view]; 
} 

điều quan trọng là đưa lớp học chính xác vào chế độ xem.

Đặt UIView nơi PlayerView có thể hoạt động trong Trình tạo giao diện nhưng sẽ không hoạt động chính xác trong mã.

Tôi hiện đang sử dụng triển khai này.

+0

tôi biết câu hỏi này đã cũ. Nhưng tôi tìm thấy điều này và sau đó đã đưa ra câu trả lời của riêng tôi. Hy vọng điều này sẽ giúp người dùng trong tương lai. –

+0

Bạn có nghĩ rằng tài sản phải mạnh mẽ không? Ý tôi là, 'UIView' đã có thuộc tính mạnh' view' chứa cùng một giá trị. Không phải là công cụ sửa đổi chỉ đọc là thích hợp hơn? – lambdas

+0

+1: Tôi nghĩ điều này là có thể. Cảm ơn bạn đã xác nhận. @ lpaul7 - Không, 'readonly' không có ý nghĩa bởi vì sau đó bạn không thể đặt thuộc tính' view' - do đó nghĩa của 'readonly'. Bạn cần có thuộc tính này là 'strong' để ghi đè thuộc tính superclass' view' (có thuộc tính khai báo 'strong'). –

23

@ lpaul7 đã được đăng một liên kết đến blog của Travis Jeffery như một bình luận, nhưng nó rất chính xác hơn nhiều so với tất cả các câu trả lời khác mà nó thực sự cần mã để có một câu trả lời:

ViewController.h:

@interface ViewController : UIViewController 

@property (strong, nonatomic) UIScrollView *view; 

@end 

ViewController.m:

@implementation ViewController 

@dynamic view; 

- (void)loadView { 
    self.view = [[UIScrollView alloc] initWithFrame:[[UIScreen mainScreen] applicationFrame]]; 
} 

@end 

Nếu bạn sử dụng xib, thay vì ghi đè loadView, hãy thay đổi kiểu chế độ xem gốc của trình điều khiển chế độ xem của bạn và thêm IBOutlet vào thuộc tính.

Xem Overriding UIViewController's View Property, Done Right để biết thêm chi tiết.

+0

Sử dụng cách tiếp cận đó tôi nhận được cảnh báo trình biên dịch sau: "loại thuộc tính 'MyScrollView *' không tương thích với kiểu 'UIView *' được kế thừa từ 'UIViewController'" – Koen

+0

@Koen Là MyScrollView của bạn là phân lớp của UIView? Bạn có nhận được cảnh báo trình biên dịch nếu bạn sử dụng UIScrollView thay vì MyScrollView? – JosephH

+0

MyScrollView là một lớp con của 'UIScrollView'. Tôi đã kết thúc làm cho scrollView chỉ là một container cho MyCustomView nơi tôi làm tất cả các bản vẽ. Trái ngược với việc làm tất cả các bản vẽ MyScrollView. – Koen

0

Nếu bất cứ ai đang Swift 2.0+, bạn có thể sử dụng phần mở rộng giao thức cho việc thực hiện tái sử dụng:

// Classes conforming to this protocol... 
protocol CustomViewProvider { 

    typealias ViewType 
} 

// ... Will get customView accessor for free 
extension CustomViewProvider where Self: UIViewController, Self.ViewType: UIView { 

    var customView: Self.ViewType { 
     return view as! Self.ViewType 
    } 
} 


// Example: 
extension HomeViewController: CustomViewProvider { 
    typealias ViewType = HomeView 
} 

// Now, we can do something like 
let customView: HomeView = HomeViewController().customView 
Các vấn đề liên quan