Tôi biết các đại biểu làm việc như thế nào và tôi biết làm thế nào tôi có thể sử dụng chúng.
Nhưng làm thế nào để tôi tạo ra chúng?
Tôi biết các đại biểu làm việc như thế nào và tôi biết làm thế nào tôi có thể sử dụng chúng.
Nhưng làm thế nào để tôi tạo ra chúng?
Câu trả lời:
Một đại biểu Objective-C là một đối tượng đã được gán cho thuộc delegate
tính một đối tượng khác. Để tạo một lớp, bạn định nghĩa một lớp thực hiện các phương thức ủy nhiệm mà bạn quan tâm và đánh dấu lớp đó là thực hiện giao thức ủy nhiệm.
Ví dụ, giả sử bạn có một UIWebView
. Nếu bạn muốn thực hiện webViewDidStartLoad:
phương thức của đại biểu , bạn có thể tạo một lớp như thế này:
@interface MyClass<UIWebViewDelegate>
// ...
@end
@implementation MyClass
- (void)webViewDidStartLoad:(UIWebView *)webView {
// ...
}
@end
Sau đó, bạn có thể tạo một phiên bản của MyClass và gán nó làm đại biểu của chế độ xem web:
MyClass *instanceOfMyClass = [[MyClass alloc] init];
myWebView.delegate = instanceOfMyClass;
Về UIWebView
phía, nó có thể có mã tương tự như thế này để xem liệu đại biểu có trả lời webViewDidStartLoad:
tin nhắn bằng cách sử dụng respondsToSelector:
và gửi nó nếu thích hợp.
if([self.delegate respondsToSelector:@selector(webViewDidStartLoad:)]) {
[self.delegate webViewDidStartLoad:self];
}
Bản thân thuộc tính ủy nhiệm thường được khai báo weak
(trong ARC) hoặc assign
(trước ARC) để tránh các vòng lặp giữ lại, vì đại biểu của một đối tượng thường giữ tham chiếu mạnh đến đối tượng đó. (Ví dụ: bộ điều khiển chế độ xem thường là đại biểu của chế độ xem mà nó chứa.)
Để xác định các đại biểu của riêng bạn, bạn sẽ phải khai báo các phương thức của họ ở đâu đó, như được thảo luận trong Apple Docs về các giao thức . Bạn thường khai báo một giao thức chính thức. Tuyên bố, được diễn giải từ UIWebView.h, sẽ giống như thế này:
@protocol UIWebViewDelegate <NSObject>
@optional
- (void)webViewDidStartLoad:(UIWebView *)webView;
// ... other methods here
@end
Điều này tương tự với một giao diện hoặc lớp cơ sở trừu tượng, vì nó tạo ra một loại đặc biệt cho đại biểu của bạn, UIWebViewDelegate
trong trường hợp này. Các đại biểu triển khai sẽ phải áp dụng giao thức này:
@interface MyClass <UIWebViewDelegate>
// ...
@end
Và sau đó thực hiện các phương thức trong giao thức. Đối với các phương thức được khai báo trong giao thức là @optional
(giống như hầu hết các phương thức ủy nhiệm), bạn cần kiểm tra -respondsToSelector:
trước khi gọi một phương thức cụ thể trên nó.
Các phương thức ủy nhiệm thường được đặt tên bắt đầu bằng tên lớp ủy nhiệm và lấy đối tượng ủy nhiệm làm tham số đầu tiên. Họ cũng thường sử dụng một hình thức di chúc, nên- hoặc đã làm. Vì vậy, webViewDidStartLoad:
(tham số đầu tiên là chế độ xem web) chứ không phải loadStarted
(không lấy tham số) chẳng hạn.
Thay vì kiểm tra xem một đại biểu có phản hồi với bộ chọn mỗi lần chúng tôi muốn nhắn tin hay không, bạn có thể lưu trữ thông tin đó khi các đại biểu được đặt. Một cách rất rõ ràng để làm điều này là sử dụng bitfield, như sau:
@protocol SomethingDelegate <NSObject>
@optional
- (void)something:(id)something didFinishLoadingItem:(id)item;
- (void)something:(id)something didFailWithError:(NSError *)error;
@end
@interface Something : NSObject
@property (nonatomic, weak) id <SomethingDelegate> delegate;
@end
@implementation Something {
struct {
unsigned int didFinishLoadingItem:1;
unsigned int didFailWithError:1;
} delegateRespondsTo;
}
@synthesize delegate;
- (void)setDelegate:(id <SomethingDelegate>)aDelegate {
if (delegate != aDelegate) {
delegate = aDelegate;
delegateRespondsTo.didFinishLoadingItem = [delegate respondsToSelector:@selector(something:didFinishLoadingItem:)];
delegateRespondsTo.didFailWithError = [delegate respondsToSelector:@selector(something:didFailWithError:)];
}
}
@end
Sau đó, trong phần thân, chúng ta có thể kiểm tra xem đại biểu của chúng ta xử lý các thông điệp bằng cách truy cập vào delegateRespondsTo
cấu trúc của chúng ta , thay vì gửi đi gửi -respondsToSelector:
lại nhiều lần.
Trước khi giao thức tồn tại, nó đã được phổ biến để sử dụng một loại trên NSObject
để khai báo các phương pháp một đại biểu có thể thực hiện. Ví dụ, CALayer
vẫn làm điều này:
@interface NSObject(CALayerDelegate)
- (void)displayLayer:(CALayer *)layer;
// ... other methods here
@end
Điều này nói với trình biên dịch rằng bất kỳ đối tượng có thể thực hiện displayLayer:
.
Sau đó, bạn sẽ sử dụng -respondsToSelector:
cách tiếp cận tương tự như được mô tả ở trên để gọi phương thức này. Các đại biểu thực hiện phương thức này và gán thuộc delegate
tính, và đó là (không có tuyên bố bạn tuân thủ giao thức). Phương pháp này phổ biến trong các thư viện của Apple, nhưng mã mới nên sử dụng cách tiếp cận giao thức hiện đại hơn ở trên, vì cách tiếp cận này gây ô nhiễm NSObject
(khiến tự động hoàn thành ít hữu ích hơn) và khiến trình biên dịch khó cảnh báo bạn về lỗi chính tả và lỗi tương tự.
unsigned int
loại thành BOOL
giá trị trả về delegate respondsToSelector
của loại BOOL
.
Câu trả lời được phê duyệt là tuyệt vời, nhưng nếu bạn đang tìm kiếm câu trả lời trong 1 phút, hãy thử điều này:
Tệp MyClass.h sẽ trông như thế này (thêm dòng đại biểu có ý kiến!)
#import <BlaClass/BlaClass.h>
@class MyClass; //define class, so protocol can see MyClass
@protocol MyClassDelegate <NSObject> //define delegate protocol
- (void) myClassDelegateMethod: (MyClass *) sender; //define delegate method to be implemented within another class
@end //end protocol
@interface MyClass : NSObject {
}
@property (nonatomic, weak) id <MyClassDelegate> delegate; //define MyClassDelegate as delegate
@end
Tệp MyClass.m sẽ trông như thế này
#import "MyClass.h"
@implementation MyClass
@synthesize delegate; //synthesise MyClassDelegate delegate
- (void) myMethodToDoStuff {
[self.delegate myClassDelegateMethod:self]; //this will call the method implemented in your other class
}
@end
Để sử dụng đại biểu của bạn trong một lớp khác (UIViewControll gọi là MyVC trong trường hợp này) MyVC.h:
#import "MyClass.h"
@interface MyVC:UIViewController <MyClassDelegate> { //make it a delegate for MyClassDelegate
}
MyVC.m:
myClass.delegate = self; //set its delegate to self somewhere
Thực hiện phương pháp đại biểu
- (void) myClassDelegateMethod: (MyClass *) sender {
NSLog(@"Delegates are great!");
}
myClass
khởi tạo bên trong MyVC.m?
Khi sử dụng phương thức giao thức chính thức để tạo hỗ trợ cho đại biểu, tôi đã thấy rằng bạn có thể đảm bảo kiểm tra loại thích hợp (mặc dù, thời gian chạy, không phải biên dịch thời gian) bằng cách thêm một cái gì đó như:
if (![delegate conformsToProtocol:@protocol(MyDelegate)]) {
[NSException raise:@"MyDelegate Exception"
format:@"Parameter does not conform to MyDelegate protocol at line %d", (int)__LINE__];
}
trong mã truy cập đại biểu (setDelegate) của bạn. Điều này giúp giảm thiểu sai lầm.
Xin vui lòng! kiểm tra hướng dẫn từng bước đơn giản dưới đây để hiểu cách các Đại biểu hoạt động trong iOS.
Tôi đã tạo hai ViewControllers (để gửi dữ liệu từ người này sang người khác)
Có lẽ đây là nhiều hơn những gì bạn đang thiếu:
Nếu bạn đến từ một quan điểm như C ++, các đại biểu sẽ quen một chút - nhưng về cơ bản, 'họ chỉ hoạt động'.
Cách thức hoạt động là bạn đặt một số đối tượng mà bạn đã viết làm đại biểu cho NSWindow, nhưng đối tượng của bạn chỉ có các triển khai (phương thức) cho một hoặc một vài trong số nhiều phương thức ủy nhiệm có thể. Vì vậy, một cái gì đó xảy ra và NSWindow
muốn gọi đối tượng của bạn - nó chỉ sử dụng respondsToSelector
phương thức của Objective-c để xác định xem đối tượng của bạn có muốn phương thức đó được gọi không, và sau đó gọi nó. Đây là cách hoạt động của object-c - các phương thức được tìm kiếm theo yêu cầu.
Hoàn toàn không quan trọng để làm điều này với các đối tượng của riêng bạn, không có gì đặc biệt xảy ra, ví dụ bạn có thể có NSArray
27 đối tượng, tất cả các loại đối tượng khác nhau, chỉ có 18 đối tượng trong số đó có -(void)setToBue;
9 phương pháp khác. Vì vậy, để kêu gọi setToBlue
tất cả 18 người cần thực hiện, đại loại như thế này:
for (id anObject in myArray)
{
if ([anObject respondsToSelector:@selector(@"setToBlue")])
[anObject setToBlue];
}
Một điều khác về các đại biểu là chúng không được giữ lại, vì vậy bạn luôn phải đặt đại biểu nil
theo MyClass dealloc
phương thức của mình .
Theo thông lệ tốt được Apple khuyến nghị, sẽ tốt cho đại biểu (theo giao thức, theo định nghĩa), phù hợp với NSObject
giao thức.
@protocol MyDelegate <NSObject>
...
@end
& để tạo các phương thức tùy chọn trong đại biểu của bạn (nghĩa là các phương thức không nhất thiết phải được triển khai), bạn có thể sử dụng @optional
chú thích như thế này:
@protocol MyDelegate <NSObject>
...
...
// Declaration for Methods that 'must' be implemented'
...
...
@optional
...
// Declaration for Methods that 'need not necessarily' be implemented by the class conforming to your delegate
...
@end
Vì vậy, khi sử dụng các phương thức mà bạn đã chỉ định là tùy chọn, bạn cần (trong lớp) kiểm tra respondsToSelector
xem chế độ xem (có phù hợp với đại biểu của bạn) có thực sự thực hiện (các) phương thức tùy chọn của bạn hay không.
Tôi nghĩ rằng tất cả những câu trả lời này rất có ý nghĩa một khi bạn hiểu các đại biểu. Cá nhân tôi đến từ vùng đất của C / C ++ và trước đó các ngôn ngữ thủ tục như Fortran, v.v ... đây là 2 phút tôi tìm kiếm các chất tương tự tương tự trong mô hình C ++.
Nếu tôi giải thích các đại biểu cho một lập trình viên C ++ / Java, tôi sẽ nói
Đại biểu là gì? Đây là những con trỏ tĩnh đến các lớp trong một lớp khác. Khi bạn gán một con trỏ, bạn có thể gọi các hàm / phương thức trong lớp đó. Do đó, một số hàm của lớp của bạn được "ủy nhiệm" (Trong thế giới C ++ - con trỏ tới bởi một con trỏ đối tượng lớp) cho một lớp khác.
Giao thức là gì? Về mặt khái niệm, nó phục vụ mục đích tương tự như tệp tiêu đề của lớp bạn đang chỉ định làm lớp đại biểu. Giao thức là một cách rõ ràng để xác định phương thức nào cần được thực hiện trong lớp mà con trỏ được đặt làm đại biểu trong một lớp.
Làm thế nào tôi có thể làm một cái gì đó tương tự trong C ++? Nếu bạn đã cố gắng thực hiện điều này trong C ++, bạn sẽ bằng cách định nghĩa các con trỏ tới các lớp (đối tượng) trong định nghĩa lớp và sau đó nối chúng với các lớp khác sẽ cung cấp các hàm bổ sung như là đại biểu cho lớp cơ sở của bạn. Nhưng hệ thống dây này cần phải được xử lý trong mã và sẽ vụng về và dễ bị lỗi. Mục tiêu C chỉ cho rằng các lập trình viên không giỏi nhất trong việc duy trì số thập phân này và cung cấp các hạn chế của trình biên dịch để thực thi một triển khai sạch.
Một đại biểu chỉ là một lớp thực hiện một số công việc cho một lớp khác. Đọc đoạn mã sau để biết ví dụ Playground hơi ngớ ngẩn (nhưng hy vọng sẽ khai sáng) cho thấy cách thức này được thực hiện trong Swift.
// A protocol is just a list of methods (and/or properties) that must
// be used by any class that adopts the protocol.
protocol OlderSiblingDelegate: class {
// This protocol only defines one required method
func getYourNiceOlderSiblingAGlassOfWater() -> String
}
class BossyBigBrother {
// The delegate is the BossyBigBrother's slave. This position can
// be assigned later to whoever is available (and conforms to the
// protocol).
weak var delegate: OlderSiblingDelegate?
func tellSomebodyToGetMeSomeWater() -> String? {
// The delegate is optional because there might not be anyone
// nearby to boss around.
return delegate?.getYourNiceOlderSiblingAGlassOfWater()
}
}
// PoorLittleSister conforms to the OlderSiblingDelegate protocol
class PoorLittleSister: OlderSiblingDelegate {
// This method is repquired by the protocol, but the protocol said
// nothing about how it needs to be implemented.
func getYourNiceOlderSiblingAGlassOfWater() -> String {
return "Go get it yourself!"
}
}
// initialize the classes
let bigBro = BossyBigBrother()
let lilSis = PoorLittleSister()
// Set the delegate
// bigBro could boss around anyone who conforms to the
// OlderSiblingDelegate protocol, but since lilSis is here,
// she is the unlucky choice.
bigBro.delegate = lilSis
// Because the delegate is set, there is a class to do bigBro's work for him.
// bigBro tells lilSis to get him some water.
if let replyFromLilSis = bigBro.tellSomebodyToGetMeSomeWater() {
print(replyFromLilSis) // "Go get it yourself!"
}
Trong thực tế, đại biểu thường được sử dụng trong các tình huống sau
Các lớp không cần biết bất cứ điều gì về nhau trước ngoại trừ lớp đại biểu phù hợp với giao thức được yêu cầu.
Tôi rất khuyên bạn nên đọc hai bài viết sau. Họ đã giúp tôi hiểu các đại biểu thậm chí còn tốt hơn các tài liệu đã làm.
Ok, đây không thực sự là một câu trả lời cho câu hỏi, nhưng nếu bạn đang tìm cách làm đại biểu của riêng mình thì có lẽ điều gì đó đơn giản hơn nhiều có thể là một câu trả lời tốt hơn cho bạn.
Tôi hầu như không thực hiện các đại biểu của mình vì tôi hiếm khi cần. Tôi chỉ có thể có MỘT đại biểu cho một đối tượng đại biểu. Vì vậy, nếu bạn muốn đại biểu của mình truyền thông / truyền dữ liệu một chiều hơn bạn sẽ thông báo tốt hơn nhiều.
NSNotification có thể truyền các đối tượng cho nhiều người nhận và nó rất dễ sử dụng. Nó hoạt động như thế này:
Tệp MyClass.m sẽ trông như thế này
#import "MyClass.h"
@implementation MyClass
- (void) myMethodToDoStuff {
//this will post a notification with myClassData (NSArray in this case) in its userInfo dict and self as an object
[[NSNotificationCenter defaultCenter] postNotificationName:@"myClassUpdatedData"
object:self
userInfo:[NSDictionary dictionaryWithObject:selectedLocation[@"myClassData"] forKey:@"myClassData"]];
}
@end
Để sử dụng thông báo của bạn trong các lớp khác: Thêm lớp làm người quan sát:
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(otherClassUpdatedItsData:) name:@"myClassUpdatedData" object:nil];
Thực hiện bộ chọn:
- (void) otherClassUpdatedItsData:(NSNotification *)note {
NSLog(@"*** Other class updated its data ***");
MyClass *otherClass = [note object]; //the object itself, you can call back any selector if you want
NSArray *otherClassData = [note userInfo][@"myClassData"]; //get myClass data object and do whatever you want with it
}
Đừng quên xóa lớp của bạn như một người quan sát nếu
- (void)dealloc
{
[[NSNotificationCenter defaultCenter] removeObserver:self];
}
giả sử bạn có một lớp mà bạn đã phát triển và muốn khai báo một thuộc tính đại biểu để có thể thông báo cho nó khi một số sự kiện xảy ra:
@class myClass;
@protocol myClassDelegate <NSObject>
-(void)myClass:(MyClass*)myObject requiredEventHandlerWithParameter:(ParamType*)param;
@optional
-(void)myClass:(MyClass*)myObject optionalEventHandlerWithParameter:(ParamType*)param;
@end
@interface MyClass : NSObject
@property(nonatomic,weak)id< MyClassDelegate> delegate;
@end
do đó, bạn khai báo một giao thức trong MyClass
tệp tiêu đề (hoặc một tệp tiêu đề riêng) và khai báo các trình xử lý sự kiện bắt buộc / tùy chọn mà đại biểu của bạn phải / nên thực hiện, sau đó khai báo một thuộc tính MyClass
thuộc loại ( id< MyClassDelegate>
) có nghĩa là bất kỳ lớp c mục tiêu nào phù hợp với giao thức MyClassDelegate
, bạn sẽ nhận thấy rằng thuộc tính của đại biểu được khai báo là yếu, điều này rất quan trọng để ngăn chặn chu kỳ giữ lại (thường xuyên nhất là đại biểu giữ lạiMyClass
thể hiện, vì vậy nếu bạn tuyên bố đại biểu là giữ lại, cả hai sẽ giữ lại lẫn nhau trong số họ sẽ được phát hành).
bạn cũng sẽ nhận thấy rằng các phương thức giao thức chuyển MyClass
thể hiện cho đại biểu làm tham số, đây là cách tốt nhất trong trường hợp đại biểu muốn gọi một số phương thức trên MyClass
cá thể và cũng giúp khi đại biểu tuyên bố chính nó như MyClassDelegate
nhiều MyClass
trường hợp, như khi bạn có nhiều UITableView's
các trường hợp trong của bạn ViewController
và tuyên bố chính nó như là một UITableViewDelegate
cho tất cả chúng.
và bên trong MyClass
bạn thông báo cho đại biểu với các sự kiện được tuyên bố như sau:
if([_delegate respondsToSelector:@selector(myClass: requiredEventHandlerWithParameter:)])
{
[_delegate myClass:self requiredEventHandlerWithParameter:(ParamType*)param];
}
trước tiên bạn kiểm tra xem đại biểu của bạn có phản hồi với phương thức giao thức mà bạn sắp gọi trong trường hợp đại biểu không thực hiện hay không và ứng dụng sẽ sập sau đó (ngay cả khi phương thức giao thức được yêu cầu).
Đây là một phương pháp đơn giản để tạo đại biểu
Tạo giao thức trong tệp .h. Đảm bảo rằng nó được xác định trước giao thức bằng cách sử dụng @ class theo sau là tên của UIViewControll< As the protocol I am going to use is UIViewController class>.
Bước: 1: Tạo một Giao thức lớp mới có tên "YourViewControll", đây sẽ là lớp con của lớp UIViewContoder và gán lớp này cho ViewContoder thứ hai.
Bước: 2: Chuyển đến tệp "YourViewControll" và sửa đổi nó như dưới đây:
#import <UIKit/UIkit.h>
@class YourViewController;
@protocol YourViewController Delegate <NSObject>
@optional
-(void)defineDelegateMethodName: (YourViewController *) controller;
@required
-(BOOL)delegateMethodReturningBool: (YourViewController *) controller;
@end
@interface YourViewController : UIViewController
//Since the property for the protocol could be of any class, then it will be marked as a type of id.
@property (nonatomic, weak) id< YourViewController Delegate> delegate;
@end
Các phương thức được xác định trong hành vi giao thức có thể được kiểm soát với @optional và @required như một phần của định nghĩa giao thức.
Bước: 3: Thực hiện Đại biểu
#import "delegate.h"
@interface YourDelegateUser ()
<YourViewControllerDelegate>
@end
@implementation YourDelegateUser
- (void) variousFoo {
YourViewController *controller = [[YourViewController alloc] init];
controller.delegate = self;
}
-(void)defineDelegateMethodName: (YourViewController *) controller {
// handle the delegate being called here
}
-(BOOL)delegateMethodReturningBool: (YourViewController *) controller {
// handle the delegate being called here
return YES;
}
@end
// kiểm tra xem phương thức đã được xác định trước khi bạn gọi nó chưa
- (void) someMethodToCallDelegate {
if ([[self delegate] respondsToSelector:@selector(defineDelegateMethodName:)]) {
[self.delegate delegateMethodName:self];
}
}
Để tạo đại biểu của riêng bạn, trước tiên bạn cần tạo một giao thức và khai báo các phương thức cần thiết mà không cần thực hiện. Và sau đó thực hiện giao thức này vào lớp tiêu đề của bạn, nơi bạn muốn thực hiện các phương thức ủy nhiệm hoặc ủy nhiệm.
Một giao thức phải được khai báo như sau:
@protocol ServiceResponceDelegate <NSObject>
- (void) serviceDidFailWithRequestType:(NSString*)error;
- (void) serviceDidFinishedSucessfully:(NSString*)success;
@end
Đây là lớp dịch vụ trong đó một số nhiệm vụ nên được thực hiện. Nó chỉ ra cách xác định đại biểu và cách đặt đại biểu. Trong lớp thực hiện sau khi nhiệm vụ hoàn thành, các phương thức được gọi.
@interface ServiceClass : NSObject
{
id <ServiceResponceDelegate> _delegate;
}
- (void) setDelegate:(id)delegate;
- (void) someTask;
@end
@implementation ServiceClass
- (void) setDelegate:(id)delegate
{
_delegate = delegate;
}
- (void) someTask
{
/*
perform task
*/
if (!success)
{
[_delegate serviceDidFailWithRequestType:@”task failed”];
}
else
{
[_delegate serviceDidFinishedSucessfully:@”task success”];
}
}
@end
Đây là lớp khung nhìn chính từ đó lớp dịch vụ được gọi bằng cách đặt ủy nhiệm cho chính nó. Và giao thức cũng được thực hiện trong lớp tiêu đề.
@interface viewController: UIViewController <ServiceResponceDelegate>
{
ServiceClass* _service;
}
- (void) go;
@end
@implementation viewController
//
//some methods
//
- (void) go
{
_service = [[ServiceClass alloc] init];
[_service setDelegate:self];
[_service someTask];
}
Đó là nó, và bằng cách thực hiện các phương thức ủy nhiệm trong lớp này, điều khiển sẽ quay trở lại sau khi hoàn thành thao tác / tác vụ.
Disclaimer: đây là Swift
phiên bản của cách tạo a delegate
.
Vậy, đại biểu là gì? Trong quá trình phát triển phần mềm, có các kiến trúc giải pháp có thể tái sử dụng chung giúp giải quyết các vấn đề thường xảy ra trong một bối cảnh nhất định, các mẫu này, vì thế, được biết đến như là các mẫu thiết kế. Đại biểu là một mẫu thiết kế cho phép một đối tượng gửi tin nhắn đến đối tượng khác khi một sự kiện cụ thể xảy ra. Tưởng tượng một đối tượng A gọi một đối tượng B để thực hiện một hành động. Khi hành động hoàn tất, đối tượng A nên biết rằng B đã hoàn thành nhiệm vụ và thực hiện hành động cần thiết, điều này có thể đạt được với sự giúp đỡ của các đại biểu!
Để giải thích rõ hơn, tôi sẽ chỉ cho bạn cách tạo một đại biểu tùy chỉnh chuyển dữ liệu giữa các lớp, với Swift trong một ứng dụng đơn giản, bắt đầu bằng cách tải xuống hoặc nhân bản dự án khởi động này và chạy nó!
Bạn có thể thấy một ứng dụng có hai lớp ViewController A
và ViewController B
. B có hai chế độ xem trên tap thay đổi màu nền của ViewController
, không có gì quá phức tạp phải không? bây giờ chúng ta hãy nghĩ một cách dễ dàng để thay đổi màu nền của lớp A khi các khung nhìn trên lớp B được nhấn.
Vấn đề là các quan điểm này là một phần của lớp B và không biết gì về lớp A, vì vậy chúng ta cần tìm cách giao tiếp giữa hai lớp này và đó là nơi phái đoàn tỏa sáng. Tôi chia việc thực hiện thành 6 bước để bạn có thể sử dụng nó như một bảng cheat khi bạn cần.
Bước 1: Tìm kiếm dấu pragma bước 1 trong tệp ClassBVC và thêm phần này
//MARK: step 1 Add Protocol here.
protocol ClassBVCDelegate: class {
func changeBackgroundColor(_ color: UIColor?)
}
Bước đầu tiên là tạo một protocol
, trong trường hợp này, chúng tôi sẽ tạo giao thức trong lớp B, bên trong giao thức bạn có thể tạo bao nhiêu chức năng mà bạn muốn dựa trên yêu cầu thực hiện của bạn. Trong trường hợp này, chúng ta chỉ có một hàm đơn giản chấp nhận một tùy chọn UIColor
làm đối số. Đây là một cách thực hành tốt để đặt tên cho các giao thức của bạn thêm từ delegate
ở cuối tên lớp, trong trường hợp này , ClassBVCDelegate
.
Bước 2: Tìm kiếm dấu pragma bước 2 ClassVBC
và thêm phần này
//MARK: step 2 Create a delegate property here.
weak var delegate: ClassBVCDelegate?
Ở đây chúng ta chỉ cần tạo một thuộc tính đại biểu cho lớp, thuộc tính này phải áp dụng protocol
loại và nó phải là tùy chọn. Ngoài ra, bạn nên thêm từ khóa yếu trước thuộc tính để tránh chu kỳ lưu giữ và rò rỉ bộ nhớ tiềm năng, nếu bạn không biết điều đó có nghĩa là không lo lắng bây giờ, chỉ cần nhớ thêm từ khóa này.
Bước 3: Hãy tìm những bước đánh dấu pragma 3 bên trong handleTap method
trong ClassBVC
và thêm này
//MARK: step 3 Add the delegate method call here.
delegate?.changeBackgroundColor(tapGesture.view?.backgroundColor)
Một điều mà bạn nên biết, chạy ứng dụng và nhấn vào bất kỳ chế độ xem nào, bạn sẽ không thấy bất kỳ hành vi mới nào và điều đó đúng nhưng điều tôi muốn chỉ ra là ứng dụng không bị lỗi khi đại biểu được gọi và đó là vì chúng tôi tạo ra nó như một giá trị tùy chọn và đó là lý do tại sao nó không bị sập ngay cả khi được ủy quyền chưa tồn tại. Bây giờ chúng ta hãy đi đến ClassAVC
tập tin và làm cho nó, ủy thác.
Bước 4: Tìm kiếm dấu pragma bước 4 bên trong phương thức handleTap ClassAVC
và thêm cái này bên cạnh loại lớp của bạn như thế này.
//MARK: step 4 conform the protocol here.
class ClassAVC: UIViewController, ClassBVCDelegate {
}
Bây giờ ClassAVC đã thông qua ClassBVCDelegate
giao thức, bạn có thể thấy rằng trình biên dịch của bạn đang báo lỗi cho bạn rằng Loại Loại 'ClassAVC không tuân thủ giao thức' ClassBVCDelegate 'và điều này chỉ có nghĩa là bạn chưa sử dụng các phương thức của giao thức, hãy tưởng tượng rằng Khi lớp A chấp nhận giao thức cũng giống như ký hợp đồng với lớp B và hợp đồng này nói rằng Bất kỳ lớp nào chấp nhận tôi PHẢI sử dụng các chức năng của tôi!
Lưu ý nhanh: Nếu bạn đến từ một Objective-C
nền tảng, có lẽ bạn đang nghĩ rằng bạn cũng có thể tắt lỗi đó làm cho phương thức đó trở thành tùy chọn, nhưng đối với tôi, và có lẽ là của bạn, Swift
ngôn ngữ không hỗ trợ tùy chọn protocols
, nếu bạn muốn làm điều đó, bạn có thể tạo một tiện ích mở rộng cho bạn protocol
hoặc sử dụng từ khóa @objc trong protocol
quá trình triển khai của bạn .
Cá nhân, nếu tôi phải tạo một giao thức với các phương thức tùy chọn khác nhau, tôi muốn chia nó thành khác nhau protocols
, theo cách đó tôi sẽ tuân theo khái niệm trao một trách nhiệm duy nhất cho các đối tượng của mình, nhưng nó có thể thay đổi dựa trên việc triển khai cụ thể.
đây là một bài viết tốt về các phương pháp tùy chọn.
Bước 5: Tìm dấu pragma bước 5 bên trong chuẩn bị cho phương thức segue và thêm phần này
//MARK: step 5 create a reference of Class B and bind them through the `prepareforsegue` method.
if let nav = segue.destination as? UINavigationController, let classBVC = nav.topViewController as? ClassBVC {
classBVC.delegate = self
}
Ở đây chúng ta chỉ tạo một thể hiện ClassBVC
và gán đại biểu của nó cho bản thân, nhưng bản thân ở đây là gì? tốt, bản thân là ClassAVC
cái đã được ủy thác!
Bước 6: Cuối cùng, hãy tìm pragma bước 6 ClassAVC
và sử dụng các chức năng của protocol
, bắt đầu nhập func changeBackgroundColor và bạn sẽ thấy rằng nó tự động hoàn thành nó cho bạn. Bạn có thể thêm bất kỳ triển khai nào bên trong nó, trong ví dụ này, chúng tôi sẽ chỉ thay đổi màu nền, thêm phần này.
//MARK: step 6 finally use the method of the contract
func changeBackgroundColor(_ color: UIColor?) {
view.backgroundColor = color
}
Bây giờ chạy ứng dụng!
Delegates
có ở khắp mọi nơi và bạn có thể sử dụng chúng mà không cần thông báo, nếu bạn tạo một đoàn tableview
trong quá khứ bạn đã sử dụng, nhiều lớp UIKIT
công việc xung quanh chúng và nhiều lớp khác frameworks
nữa, chúng sẽ giải quyết những vấn đề chính này.
Xin chúc mừng, bạn chỉ cần thực hiện một đại biểu tùy chỉnh, tôi biết rằng có lẽ bạn đang suy nghĩ, rất nhiều rắc rối chỉ cho việc này? tốt, ủy quyền là một mẫu thiết kế rất quan trọng để hiểu nếu bạn muốn trở thành một iOS
nhà phát triển và luôn ghi nhớ rằng họ có mối quan hệ 1-1 giữa các đối tượng.
Bạn có thể xem hướng dẫn ban đầu ở đây
Câu trả lời thực sự đã được trả lời, nhưng tôi muốn đưa cho bạn một "bảng cheat" để tạo một đại biểu:
DELEGATE SCRIPT
CLASS A - Where delegate is calling function
@protocol <#Protocol Name#> <NSObject>
-(void)delegateMethod;
@end
@interface <#Some ViewController#> : <#UIViewController#>
@property (nonatomic, assign) id <<#Protocol Name#>> delegate;
@end
@implementation <#Some ViewController#>
-(void)someMethod {
[self.delegate methodName];
}
@end
CLASS B - Where delegate is called
@interface <#Other ViewController#> (<#Delegate Name#>) {}
@end
@implementation <#Other ViewController#>
-(void)otherMethod {
CLASSA *classA = [[CLASSA alloc] init];
[classA setDelegate:self];
}
-delegateMethod() {
}
@end
ViewControll.h
@protocol NameDelegate <NSObject>
-(void)delegateMEthod: (ArgType) arg;
@end
@property id <NameDelegate> delegate;
ViewControll.m
[self.delegate delegateMEthod: argument];
MainViewControll.m
ViewController viewController = [ViewController new];
viewController.delegate = self;
Phương pháp:
-(void)delegateMEthod: (ArgType) arg{
}
Theo quan điểm của tôi, tạo lớp riêng cho phương thức ủy nhiệm đó và bạn có thể sử dụng nơi bạn muốn.
trong DropDownClass.h tùy chỉnh của tôi
typedef enum
{
DDSTATE,
DDCITY
}DropDownType;
@protocol DropDownListDelegate <NSObject>
@required
- (void)dropDownDidSelectItemWithString:(NSString*)itemString DropDownType:(DropDownType)dropDownType;
@end
@interface DropDownViewController : UIViewController
{
BOOL isFiltered;
}
@property (nonatomic, assign) DropDownType dropDownType;
@property (weak) id <DropDownListDelegate> delegate;
@property (strong, nonatomic) NSMutableArray *array1DropDown;
@property (strong, nonatomic) NSMutableArray *array2DropDown;
sau đó tệp in.m tạo mảng với các đối tượng,
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath{
CGFloat rowHeight = 44.0f;
return rowHeight;
}
-(NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{
return isFiltered?[self.array1DropDown count]:[self.array2DropDown count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *simpleTableIdentifier = @"TableCell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:simpleTableIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:simpleTableIdentifier];
}
if (self.delegate) {
if (self.dropDownType == DDCITY) {
cell.textLabel.text = [self.array1DropDown objectAtIndex:indexPath.row];
}
else if (self.dropDownType == DDSTATE) {
cell.textLabel.text = [self.array2DropDown objectAtIndex:indexPath.row];
}
}
return cell;
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
[self dismissViewControllerAnimated:YES completion:^{
if(self.delegate){
if(self.dropDownType == DDCITY){
[self.delegate dropDownDidSelectItemWithString:[self.array1DropDown objectAtIndex:indexPath.row] DropDownType:self.dropDownType];
}
else if (self.dropDownType == DDSTATE) {
[self.delegate dropDownDidSelectItemWithString:[self.array2DropDown objectAtIndex:indexPath.row] DropDownType:self.dropDownType];
}
}
}];
}
Ở đây tất cả được đặt cho lớp đại biểu tùy chỉnh. Sau đó bạn có thể sử dụng phương thức ủy nhiệm này ở nơi bạn muốn. Ví dụ ...
sau khi nhập bộ điều khiển khung nhìn khác của tôi sau đó
tạo hành động để gọi phương thức ủy nhiệm như thế này
- (IBAction)dropDownBtn1Action:(id)sender {
DropDownViewController *vehicleModelDropView = [[DropDownViewController alloc]init];
vehicleModelDropView.dropDownType = DDCITY;
vehicleModelDropView.delegate = self;
[self presentViewController:vehicleModelDropView animated:YES completion:nil];
}
sau đó gọi phương thức đại biểu như thế này
- (void)dropDownDidSelectItemWithString:(NSString *)itemString DropDownType:(DropDownType)dropDownType {
switch (dropDownType) {
case DDCITY:{
if(itemString.length > 0){
//Here i am printing the selected row
[self.dropDownBtn1 setTitle:itemString forState:UIControlStateNormal];
}
}
break;
case DDSTATE: {
//Here i am printing the selected row
[self.dropDownBtn2 setTitle:itemString forState:UIControlStateNormal];
}
default:
break;
}
}
Đại biểu: - Tạo
@protocol addToCartDelegate <NSObject>
-(void)addToCartAction:(ItemsModel *)itemsModel isAdded:(BOOL)added;
@end
Gửi và vui lòng chỉ định đại biểu để xem bạn đang gửi dữ liệu
[self.delegate addToCartAction:itemsModel isAdded:YES];
//1.
//Custom delegate
@protocol TB_RemovedUserCellTag <NSObject>
-(void)didRemoveCellWithTag:(NSInteger)tag;
@end
//2.
//Create a weak reference in a class where you declared the delegate
@property(weak,nonatomic)id <TB_RemovedUserCellTag> removedCellTagDelegate;
//3.
// use it in the class
[self.removedCellTagDelegate didRemoveCellWithTag:self.tag];
//4. import the header file in the class where you want to conform to the protocol
@interface MyClassUsesDelegate ()<TB_RemovedUserCellTag>
@end
// 5. Thực hiện phương thức trong lớp .m - (void) didRemoveCellWithTag: (NSInteger) tag {NSLog @ ("Tag% d", tag);
}
Hãy bắt đầu với một ví dụ, nếu chúng tôi mua một sản phẩm trực tuyến, nó sẽ trải qua các quy trình như vận chuyển / giao hàng được xử lý bởi các nhóm khác nhau. Vì vậy, nếu việc vận chuyển được hoàn thành, nhóm vận chuyển nên thông báo cho nhóm giao hàng và nó sẽ được truyền thông một đến một khi truyền thông tin này sẽ là chi phí chung cho những người khác / nhà cung cấp có thể chỉ muốn truyền thông tin này cho những người được yêu cầu.
Vì vậy, nếu chúng tôi nghĩ về ứng dụng của mình, một sự kiện có thể là một đơn đặt hàng trực tuyến & các nhóm khác nhau có thể giống như nhiều lượt xem.
Dưới đây là mã coi ShippingView là nhóm Vận chuyển & DeliveryView là nhóm giao hàng:
//Declare the protocol with functions having info which needs to be communicated
protocol ShippingDelegate : class {
func productShipped(productID : String)
}
//shippingView which shows shipping status of products
class ShippingView : UIView
{
weak var delegate:ShippingDelegate?
var productID : String
@IBAction func checkShippingStatus(sender: UIButton)
{
// if product is shipped
delegate?.productShipped(productID: productID)
}
}
//Delivery view which shows delivery status & tracking info
class DeliveryView: UIView,ShippingDelegate
{
func productShipped(productID : String)
{
// update status on view & perform delivery
}
}
//Main page on app which has both views & shows updated info on product whole status
class ProductViewController : UIViewController
{
var shippingView : ShippingView
var deliveryView : DeliveryView
override func viewDidLoad() {
super.viewDidLoad()
// as we want to update shipping info on delivery view, so assign delegate to delivery object
// whenever shipping status gets updated it will call productShipped method in DeliveryView & update UI.
shippingView.delegate = deliveryView
//
}
}