Các phương thức được bảo vệ trong Objective-C


112

Tương đương với các phương thức được bảo vệ trong Objective-C là gì? Tôi muốn xác định các phương thức mà chỉ các lớp dẫn xuất mới có thể gọi / thực hiện.

Câu trả lời:


47

Bạn không thể khai báo một phương thức được bảo vệ hoặc riêng tư. Bản chất động của Objective-C làm cho nó không thể thực hiện các điều khiển truy cập cho các phương thức. (Bạn có thể làm điều đó bằng cách sửa đổi nhiều trình biên dịch hoặc thời gian chạy, với một hình phạt tốc độ nghiêm trọng, nhưng vì những lý do rõ ràng, điều này không được thực hiện.)

Lấy từ Nguồn .


Về mặt kỹ thuật, bạn không thể, bạn có thể mô phỏng các biến riêng.
Sharen Eayrs

Lee - nếu bạn khai báo một con trỏ hàm trong @protected và gán một hàm trong phương thức init thì nó có hoạt động không?
bikram990

156

Bạn có thể mô phỏng quyền truy cập được bảo vệ và riêng tư vào các phương thức bằng cách thực hiện như sau:

  • Khai báo các phương thức riêng tư của bạn trong phần mở rộng lớp (tức là một danh mục chưa được đặt tên được khai báo gần đầu tệp .m của lớp)
  • Khai báo các phương thức được bảo vệ của bạn trong tiêu đề Lớp con - Apple sử dụng mẫu này đối với UIGestureRecognizer (xem tài liệu và tham chiếu đến UIGestureRecognizerSubclass.h)

Các biện pháp bảo vệ này, như Sachin đã lưu ý, không được thực thi trong thời gian chạy (ví dụ như trong Java).


2
Giới thiệu về giải pháp giống UIGestureRecognizer: Vấn đề là nếu một số mã nhập lớp con, nó cũng sẽ nhập tiêu đề Lớp con và do đó nó sẽ có quyền truy cập vào các phương thức "được bảo vệ". Có cách nào để giải quyết vấn đề đó không?
yonix

5
Xin chào yonix, quá trình nhập cho tiêu đề lớp con sẽ được thực hiện bên trong tệp .m chứ không phải bên trong tệp .h, vì vậy việc nhập lớp con sẽ không nhập các phương thức được bảo vệ này.
Brian Westphal

Đề xuất thú vị Brian, cảm ơn rất nhiều !! Để các poster ban đầu, đối với tài sản đã tuyên bố, chỉ cần đảm bảo rằng bạn sử dụng @dynamic trong phần mở rộng lớp của lớp con (loại giấu tên) thực hiện, do đó trong thời gian chạy, thực hiện của lớp cha sẽ được sử dụng
user1046037

1
Làm cách nào để xem UIGestureRecognizerSubclass.h?
Sharen Eayrs

5
Cảm ơn bạn đã chỉ ra về cách Apple thực hiện nó trong nội bộ. Tôi gửi một ví dụ đầy đủ về cách để thực hiện những thứ giống như cách Apple đã làm trongUIGestureRecognizerSubclass.h
bẩn Henry

14

Đây là những gì tôi đã làm để hiển thị các phương thức được bảo vệ đối với các lớp con của mình mà không yêu cầu chúng thực hiện chính các phương thức đó. Điều này có nghĩa là tôi không nhận được cảnh báo trình biên dịch trong lớp con của mình về việc triển khai chưa hoàn thành.

SuperClassProtectedMethods.h (tệp giao thức):

@protocol SuperClassProtectedMethods <NSObject>
- (void) protectMethod:(NSObject *)foo;
@end

@interface SuperClass (ProtectedMethods) < SuperClassProtectedMethods >
@end

SuperClass.m: (trình biên dịch bây giờ sẽ buộc bạn thêm các phương thức được bảo vệ)

#import "SuperClassProtectedMethods.h"
@implementation SuperClass
- (void) protectedMethod:(NSObject *)foo {}
@end

SubClass.m:

#import "SuperClassProtectedMethods.h"
// Subclass can now call the protected methods, but no external classes importing .h files will be able to see the protected methods.

2
Ý nghĩa của bảo vệ là nó không thể được gọi ra bên ngoài. Bạn vẫn có thể gọi bất kỳ phương thức nào được định nghĩa trong lớp bất kể chúng có hiển thị bên ngoài hay không.
eonil,

Vâng, tôi hiểu điều này. Phương pháp này hoạt động đối với não người, không phải mã được biên dịch thực tế. Nhưng Objective-C không cho phép điều đó (không thể gọi ra bên ngoài). Bạn luôn có thể performSelectorvào nó.
Michael Kernahan

1
Bạn cũng có thể làm [(id)obj hiddenMethod]. Nói chính xác, phương pháp bảo vệ không được hỗ trợ trong Objective-C.
eonil

Vấn đề với điều này là cái gọi là các lớp được bảo vệ của bạn không thể quảng cáo thuộc tính. Nếu bạn không cần thuộc tính, thì bất kỳ ai cũng biết rằng bạn có thể chỉ cần thêm các danh mục được bảo vệ.
Sharen Eayrs

@eonil: "Bạn cũng có thể làm [(id) obj hiddenMethod]." Có, bạn có thể làm điều đó, nhưng bạn sẽ nhận được cảnh báo từ trình biên dịch, nếu phương pháp đó không có trong bất kỳ giao diện nào được bao gồm.
Kaiserludi

9

Tôi vừa phát hiện ra điều này và nó phù hợp với tôi. Để cải thiện câu trả lời của Adam, trong lớp cha của bạn, hãy thực hiện phương thức được bảo vệ trong tệp .m nhưng không khai báo nó trong tệp .h. Trong lớp con của bạn, hãy tạo một danh mục mới trong tệp .m của bạn với phần khai báo phương thức được bảo vệ của lớp cha và bạn có thể sử dụng phương thức được bảo vệ của lớp cha trong lớp con của mình. Điều này cuối cùng sẽ không ngăn người gọi phương thức được cho là được bảo vệ nếu bị ép buộc trong thời gian chạy.

/////// SuperClass.h
@interface SuperClass

@end

/////// SuperClass.m
@implementation SuperClass
- (void) protectedMethod
{}
@end

/////// SubClass.h
@interface SubClass : SuperClass
@end

/////// SubClass.m
@interface SubClass (Protected)
- (void) protectedMethod ;
@end

@implementation SubClass
- (void) callerOfProtectedMethod
{
  [self protectedMethod] ; // this will not generate warning
} 
@end

2
Trong trường hợp này, trình biên dịch vẫn đưa ra cảnh báo về phương pháp chưa hoàn thànhprotectedMethod
skywinder

Đây là một công việc tốt nhưng thay vì tạo một danh mục (Được bảo vệ), bạn có thể tạo một phần mở rộng.
Dharmesh Siddhpura

@skywinder Có thể nó đã xảy ra trong một phiên bản cũ hơn, nhưng các phiên bản hiện tại của Xcode không có vấn đề gì với giải pháp này.
Darren Ehlers

2

Một cách khác bằng cách sử dụng các biến @protected.

@interface SuperClass:NSObject{
  @protected
    SEL protectedMehodSelector;
}

- (void) hackIt;
@end

@implementation SuperClass

-(id)init{

self = [super init];
if(self) {
 protectedMethodSelector = @selector(baseHandling);
 }

return self;
}

- (void) baseHandling {

  // execute your code here
}

-(void) hackIt {

  [self performSelector: protectedMethodSelector];
}

@end

@interface SubClass:SuperClass
@end

@implementation SubClass

-(id)init{

self = [super init];
if(self) {
 protectedMethodSelector = @selector(customHandling);
 }

return self;
}

- (void) customHandling {

  // execute your custom code here
}

@end

và bạn có thể đặt Ivars được bảo hộ tại một phần mở rộng lớp trong một tập tin tiêu đề tên được bảo vệ quá
malhal

1

Bạn có thể định nghĩa phương thức như một phương thức riêng của lớp cha và có thể sử dụng [super performSelector:@selector(privateMethod)];trong lớp con.


0

Bạn có thể sắp xếp làm điều này với một danh mục.

@interface SomeClass (Protected)
-(void)doMadProtectedThings;
@end

@implementation SomeClass (Protected)

- (void)doMadProtectedThings{
    NSLog(@"As long as the .h isn't imported into a class of completely different family, these methods will never be seen. You have to import this header into the subclasses of the super instance though.");
}

@end

Các phương thức sẽ không bị ẩn nếu bạn nhập danh mục trong một lớp khác, nhưng bạn không làm như vậy. Do tính chất động của Objective-C, thực sự không thể ẩn hoàn toàn một phương thức bất kể kiểu thể hiện đang gọi.

Cách tốt nhất để thực hiện có lẽ là danh mục tiếp tục lớp như được trả lời bởi @Brian Westphal nhưng bạn sẽ phải xác định lại phương thức trong danh mục này cho từng cá thể lớp con.


0

Một tùy chọn là sử dụng phần mở rộng lớp để ẩn các phương thức.

Trong .h:

@interface SomeAppDelegate : UIResponder <UIApplicationDelegate>

@property (strong, nonatomic) UIWindow *window;

@end

Trong .m:

@interface SomeAppDelegate()
- (void)localMethod;
@end

@implementation SomeAppDelegate

- (void)localMethod
{
}

@end

Tôi không nghĩ rằng bạn thậm chí cần @interfacekhai báo trong tệp .m. Bạn chỉ có thể khai báo một hàm và sử dụng nó và nó sẽ được coi là riêng tư.
Russ

1
Lưu ý rằng điều này chỉ đúng với các bản cập nhật gần đây trong Objective C. Trước đó, bạn phải khai báo phương thức trong một giao diện nếu không ít nhất bạn sẽ nhận được cảnh báo.
Guillaume Laurent,

0

Tôi thường đặt tên phương thức được bảo vệ bằng tiền tố bên trong:

-(void) internalMethod;
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.