ios - كيف يمكنني إنشاء المفوضين في Objective-C؟




cocoa callback delegates (17)

في وجهة نظري ، قم بإنشاء فصل منفصل لهذا الأسلوب المفوض ويمكنك استخدام المكان الذي تريده.

في بلدي DropDownClass.h مخصص

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;

بعد ذلك في ملف م إنشاء مجموعة مع الكائنات ،

 - (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];
        }
    }
}];
}

Here all are set for Custom delegate class.after that you can use this delegate method where you want.for example...

in my another viewcontroller import after that

create action for calling delegate method like this

- (IBAction)dropDownBtn1Action:(id)sender {
DropDownViewController *vehicleModelDropView = [[DropDownViewController alloc]init];
vehicleModelDropView.dropDownType = DDCITY;
vehicleModelDropView.delegate = self;
[self presentViewController:vehicleModelDropView animated:YES completion:nil];
}

after that call delegate method like this

- (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;
}
}

أعرف كيف يعمل المندوبون ، وأعرف كيف يمكنني استخدامها.

لكن كيف أقوم بإنشائها؟


كممارسة جيدة أوصت بها شركة Apple ، من المفيد للمندوب (وهو بروتوكول ، بحكم التعريف) ، أن يتوافق مع بروتوكول NSObject .

@protocol MyDelegate <NSObject>
    ...
@end

ولإنشاء طرق اختيارية داخل @optional (أي الأساليب التي لا يلزم تنفيذها بالضرورة) ، يمكنك استخدام التعليق التوضيحي " @optional كما يلي:

@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

لذلك عند استخدام الطرق التي حددتها كاختيارية ، تحتاج إلى (في فصلك) التحقق من respondsToSelector إلى جهاز respondsToSelector إذا كان العرض (المتوافق مع المفوض) قد نفذ بالفعل طريقة (طرق) اختيارك الخاصة بك أم لا.


هذه طريقة بسيطة لإنشاء المندوبين

إنشاء بروتوكول في ملف .h. تأكد من أن يتم تعريفه قبل البروتوكول باستخدامclass متبوعًا باسم UIViewController < As the protocol I am going to use is UIViewController class>. سأستخدمه هو UIViewController < As the protocol I am going to use is UIViewController class>.

الخطوة: 1: إنشاء بروتوكول فئة جديدة باسم "YourViewController" والذي سيكون فئة فرعية من فئة UIViewController وتعيين هذه الفئة إلى ViewController الثاني.

الخطوة: 2: اذهب إلى ملف "YourViewController" وعدله على النحو التالي:

#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

يمكن التحكم في الطرق المحددة في سلوك البروتوكول بـoptional وrequired كجزء من تعريف البروتوكول.

الخطوة: 3: تنفيذ تفويض

    #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

// اختبار ما إذا كانت الطريقة قد تم تحديدها قبل أن تسميها

 - (void) someMethodToCallDelegate {
     if ([[self delegate] respondsToSelector:@selector(defineDelegateMethodName:)]) {
           [self.delegate delegateMethodName:self]; 
     }
  }

رجاء! تحقق أدناه خطوة بسيطة بخطوة تعليمي لفهم كيفية عمل المندوبين في iOS.

مندوب في iOS

لقد قمت بإنشاء اثنين من أجهزة التحكم في العرض (لإرسال البيانات من واحد إلى آخر)

  1. FirstViewController تنفيذ المفوض (الذي يوفر البيانات).
  2. تعلن SecondViewController المفوض (الذي سيتلقى البيانات).

الجواب المعتمد رائع ، ولكن إذا كنت تبحث عن إجابة مدتها دقيقة ، فجرب هذا:

يجب أن يبدو الملف MyClass.h مثل هذا (إضافة خطوط المفوض بتعليقات!)

#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

يجب أن يبدو الملف MyClass.m مثل هذا

#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

لاستخدام مندوبك في فصل دراسي آخر (UIViewController يسمى MyVC في هذه الحالة) 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

تنفيذ طريقة مندوب

- (void) myClassDelegateMethod: (MyClass *) sender {
    NSLog(@"Delegates are great!");
}

الإجابة هي في الواقع الإجابة ، ولكن أود أن أعطيك "ورقة الغش" لإنشاء مندوب:

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

عند استخدام طريقة البروتوكول الرسمي لإنشاء دعم للمندوبين ، وجدت أنه يمكنك التأكد من التحقق الصحيح من النوع (وإن كان ، وقت التشغيل ، وليس وقت التحويل البرمجي) بإضافة شيء مثل:

if (![delegate conformsToProtocol:@protocol(MyDelegate)]) {
    [NSException raise:@"MyDelegate Exception"
                format:@"Parameter does not conform to MyDelegate protocol at line %d", (int)__LINE__];
}

في ملحق مندوب التفويض (setDelegate) الخاص بك. هذا يساعد على تقليل الأخطاء.


أعتقد أن كل هذه الإجابات منطقية عندما تفهم المندوبين. شخصيا جئت من أرض C / C ++ وقبل تلك اللغات الإجرائية مثل Fortran الخ هنا حتى هنا هو بلدي 2 دقيقة تأخذ على إيجاد نظائرها مماثلة في نموذج C ++.

إذا كان لي أن أشرح المندوبين إلى مبرمج C ++ / Java أود أن أقول

ما هو المندوبون؟ هذه هي مؤشرات ثابتة إلى فئات داخل فئة أخرى. بمجرد تعيين مؤشر ، يمكنك استدعاء الوظائف / الأساليب في هذا الصف. ومن ثم يتم "تفويض" بعض وظائف الصف الخاص بك (في العالم C ++ - المؤشر إلى مؤشر كائن فئة) إلى فئة أخرى.

ما هي البروتوكولات؟ من الناحية المفاهيمية ، فإنها تستخدم غرضًا مشابهًا لملف الرأس للفئة التي تقوم بتعيينها كفصول مفوض. البروتوكول هو طريقة واضحة لتعريف الطرق التي يجب تنفيذها في الفصل الذي تم تعيين مؤشره كمفوض داخل الفصل.

كيف يمكنني القيام بشيء مماثل في C ++؟ إذا حاولت القيام بذلك في C ++ ، فستقوم بتعريف المؤشرات إلى فئات (كائنات) في تعريف الفئة ثم توصيلها إلى فئات أخرى توفر وظائف إضافية كمفوضين لفصلك الأساسي. لكن يجب أن يتم وضع هذه الأسلاك داخل المدونة وستكون خرقاء وعرضة للخطأ. يفترض الهدف C فقط أن المبرمجين ليسوا الأفضل في الحفاظ على هذا decipline ويوفر قيود مترجم لفرض تطبيق نظيف.


مندوب: - إنشاء

@protocol addToCartDelegate <NSObject>

-(void)addToCartAction:(ItemsModel *)itemsModel isAdded:(BOOL)added;

@end

إرسال وتعيين تفويض المفوض لعرض أنك ترسل البيانات

[self.delegate addToCartAction:itemsModel isAdded:YES];

ربما هذا أكثر على غرار ما أنت في عداد المفقودين:

إذا كنت قادماً من وجهة نظر C ++ مثل وجهة النظر ، فإن المندوبين يأخذون القليل من التعود - ولكنهم في الأساس "يعملون فقط".

الطريقة التي تعمل بها هي أن تقوم بتعيين بعض الكائنات التي كتبتها كمفوض إلى NSWindow ، لكن الكائن الخاص بك يحتوي فقط على تطبيقات (أساليب) واحدة أو عدة طرق تفويض كثيرة ممكنة. يحدث شيء ما ، وتريد NSWindow استدعاء الكائن الخاص بك - إنها تستخدم أسلوب Objective-c's NSWindow لتحديد ما إذا كان الكائن يريد هذه الطريقة ، ثم يطلق عليه. هذه هي الطريقة التي يعمل بها الهدف-ج- يتم البحث عن الطرق حسب الطلب.

من المستحيل أن تفعل ذلك مع الأشياء الخاصة بك ، لا يوجد شيء خاص يحدث ، يمكنك على سبيل المثال أن يكون NSArray من 27 NSArray ، جميع أنواع الكائنات المختلفة ، فقط 18 منها تحتوي على الطريقة -(void)setToBue; الآخر 9 لا. لذلك ، setToBlue على جميع الـ 18 الذين يحتاجون إلى القيام به ، شيء من هذا القبيل:

for (id anObject in myArray)
{
  if ([anObject respondsToSelector:@selector(@"setToBlue")])
     [anObject setToBlue]; 
}

والشيء الآخر حول المندوبين هو أنه لا يتم الاحتفاظ بها ، لذلك يجب عليك دائمًا تعيين المفوض إلى nil في طريقة MyClass dealloc الخاصة بك.


المفوض Objective-C هو كائن تم تعيينه إلى الخاصية delegate كائن آخر. لإنشاء واحدة ، يمكنك ببساطة تحديد فئة تقوم بتنفيذ أساليب التفويض التي تهمك ، وتضع علامة على تلك الفئة باعتبارها تنفذ بروتوكول التفويض.

على سبيل المثال ، افترض أن لديك UIWebView . إذا كنت ترغب في تنفيذ أسلوب webViewDidStartLoad: الخاص webViewDidStartLoad: يمكنك إنشاء فئة مثل هذه:

@interface MyClass<UIWebViewDelegate>
// ...
@end

@implementation MyClass
- (void)webViewDidStartLoad:(UIWebView *)webView { 
    // ... 
}
@end

ثم يمكنك إنشاء مثيل من MyClass وتعيينه كمفوض عرض الويب:

MyClass *instanceOfMyClass = [[MyClass alloc] init];
myWebView.delegate = instanceOfMyClass;

على الجانب UIWebView ، ربما يكون له رمز مشابه لهذا لمعرفة ما إذا كان المفوض يستجيب إلى webViewDidStartLoad: message using respondsToSelector: webViewDidStartLoad: إذا كان ذلك مناسبًا.

if([self.delegate respondsToSelector:@selector(webViewDidStartLoad:)]) {
    [self.delegate webViewDidStartLoad:self];
}

عادةً ما يتم اعتبار الخاصية المفوضة نفسها weak (في ARC) أو assign (pre-ARC) لتجنب حلقات الاحتفاظ ، نظرًا لأن مفوض كائن غالباً ما يحتفظ بمرجع قوي إلى ذلك الكائن. (على سبيل المثال ، غالباً ما تكون وحدة التحكم في العرض هي المفوض في طريقة العرض التي تحتوي عليها.)

مما يجعل المندوبين لصفوفك

لتحديد المفوضين الخاصين بك ، يجب عليك الإعلان عن أساليبها في مكان ما ، كما هو موضح في مستندات Apple على البروتوكولات . أنت عادة تعلن عن بروتوكول رسمي. الإعلان ، معاد صياغته من UIWebView.h ، سيبدو هكذا:

@protocol UIWebViewDelegate <NSObject>
@optional
- (void)webViewDidStartLoad:(UIWebView *)webView;
// ... other methods here
@end

وهذا مماثل لواجهة أو فئة أساسية مجردة ، لأنه ينشئ نوع خاص UIWebViewDelegate ، UIWebViewDelegate في هذه الحالة. سيتعين على المندوبين المفوضين اعتماد هذا البروتوكول:

@interface MyClass <UIWebViewDelegate>
// ...
@end

ثم تنفيذ الأساليب في البروتوكول. بالنسبة للطرق المعلنة في البروتوكول مثل @optional (مثل معظم طرق التفويض) ، تحتاج إلى التحقق مع -respondsToSelector: قبل الاتصال بطريقة معينة عليه.

تسمية

يتم تسمية أساليب المفوض عادةً بدءًا من اسم فئة التفويض ، وتأخذ كائن التفويض كمعامل أول. ﮐﻣﺎ أﻧﮭم ﻏﺎﻟﺑﺎً ﻣﺎ ﯾﺳﺗﺧدﻣون إرادة ، أو ﯾﺟب ، أو ﺗﺗﺧذ اﻹﺟراءات. لذلك ، webViewDidStartLoad: (المعلمة الأولى هي عرض الويب) بدلاً من loadStarted (مع عدم وجود معلمات) على سبيل المثال.

تحسين السرعة

بدلاً من التحقق مما إذا كان المفوض يستجيب إلى محدد في كل مرة نريد إرسال رسالة إليه ، يمكنك تخزين تلك المعلومات مؤقتًا عند تعيين المندوبين. طريقة واحدة نظيفة جداً للقيام بذلك هي استخدام bitfield ، كما يلي:

@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

بعد ذلك ، في الجسم ، يمكننا التحقق من أن -respondsToSelector: يتعامل مع الرسائل عن طريق الوصول إلى -respondsToSelector: ، وليس عن طريق إرسال -respondsToSelector: مرارًا وتكرارًا.

المندوبون غير الرسميين

قبل وجود البروتوكولات ، كان من الشائع استخدام category على NSObject لإعلان الطرق التي يمكن أن يقوم المفوض بتنفيذها. على سبيل المثال ، لا يزال CALayer يفعل هذا:

@interface NSObject(CALayerDelegate)
- (void)displayLayer:(CALayer *)layer;
// ... other methods here
@end

هذا يخبر بشكل أساسي المترجم بأن أي كائن قد ينفذ displayLayer:

يمكنك عندئذٍ استخدام نفس same- -respondsToSelector: كما هو موضح أعلاه لاستدعاء هذه الطريقة. يقوم المندوبون بتنفيذ هذه الطريقة ببساطة وتعيين خاصية delegate ، وهذا كل ما في الأمر (لا يوجد إعلان بأنك تتوافق مع البروتوكول). هذه الطريقة شائعة في مكتبات Apple ، لكن يجب أن تستخدم الشفرة الجديدة منهج البروتوكول الأكثر حداثة أعلاه ، لأن هذا النهج يلوث NSObject (مما يجعل الإكمال التلقائي أقل فائدة) ويجعل من الصعب على المجمع أن NSObject من الأخطاء الإملائية والأخطاء المشابهة.


ViewController.h

@protocol NameDelegate <NSObject>

-(void)delegateMEthod: (ArgType) arg;

@end

@property id <NameDelegate> delegate;

ViewController.m

[self.delegate delegateMEthod: argument];

MainViewController.m

ViewController viewController = [ViewController new];
viewController.delegate = self;

طريقة:

-(void)delegateMEthod: (ArgType) arg{
}

حسنًا ، هذه ليست في الحقيقة إجابة على السؤال ، ولكن إذا كنت تبحث عن كيفية إنشاء مندوبك الخاص ، فربما يكون إجراء شيء أكثر بساطة أفضل لك.

أنا بصعوبة نفّذ مندوبي بسبب قلبي. يمكنني الحصول على تفويض واحد فقط لكائن المفوض. لذا ، إذا كنت تريد تفويض مندوبك لبيانات الاتصال / المرور في اتجاه واحد ، فهذا أفضل بكثير من استخدام الإشعارات.

يمكن لـ NSNotification تمرير الكائنات إلى أكثر من مستلم واحد وهو سهل الاستخدام للغاية. يعمل مثل هذا:

يجب أن يظهر ملف MyClass.m مثل هذا

#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

لاستخدام الإشعار في فئات أخرى: أضف الصف كمراقب:

[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(otherClassUpdatedItsData:) name:@"myClassUpdatedData" object:nil];

تنفيذ المحدد:

- (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
}

لا تنس إزالة صفك كمراقب إذا كان

- (void)dealloc
{
    [[NSNotificationCenter defaultCenter] removeObserver:self];
}

//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. تطبيق الأسلوب في فئة .m - (void) didRemoveCellWithTag: (NSInteger) العلامة {NSLog @ ("العلامات٪ d" ، العلامة)؛

}


نسخة سويفت

المندوب هو مجرد فصل يقوم ببعض الأعمال لفصل آخر. اقرأ التعليمات البرمجية التالية لمثال Playly سخيفة إلى حد ما (ولكن نأمل أن تكون مفيدة) يوضح كيفية تنفيذ ذلك في 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!"
}

في الممارسة الفعلية ، يتم استخدام المندوبين غالبًا في الحالات التالية

  1. عندما يحتاج الفصل إلى توصيل بعض المعلومات إلى فصل آخر
  2. عندما يريد الفصل السماح لفصل آخر بتخصيصه

لا تحتاج الفصول الدراسية إلى معرفة أي شيء عن بعضها البعض مسبقًا إلا أن فئة المفوضين تتوافق مع البروتوكول المطلوب.

أنا أوصي قراءة المقالات التالية اثنين. لقد ساعدوني على فهم المندوبين حتى أفضل من documentation .


إخلاء المسؤولية: هذا هو إصدار Swift من كيفية إنشاء delegate .

إذن ما هو المندوبون؟ ... في تطوير البرمجيات ، هناك معماريات حلول عامة قابلة لإعادة الاستخدام تساعد على حل المشاكل الشائعة في سياق معين ، هذه "النماذج" ، إذا جاز التعبير ، هي أفضل ما تعرف باسم أنماط التصميم. المندوبون هم نمط تصميم يسمح لكائن واحد بإرسال رسائل إلى كائن آخر عند حدوث حدث معين. تخيل كائن A يستدعي كائن B لتنفيذ إجراء. بمجرد اكتمال الإجراء ، يجب أن يعرف الكائن A أن B قد أكمل المهمة واتخذ الإجراء اللازم ، يمكن تحقيق ذلك بمساعدة المندوبين!

للحصول على تفسير أفضل ، سوف أريكم كيفية إنشاء تفويض مخصص يقوم بتمرير البيانات بين الفئات ، باستخدام Swift في تطبيق بسيط ، ابدأ بتنزيل أو استنساخ مشروع البدء هذا وتشغيله!

يمكنك رؤية تطبيق يحتوي على فصلين ، ViewController A و ViewController B B لديه اثنين من وجهات النظر التي تغير في الصنبور لون الخلفية من ViewController ، لا شيء معقدة للغاية أليس كذلك؟ حسنا الآن دعونا نفكر بطريقة سهلة لتغيير لون الخلفية من الفئة (أ) عندما يتم استغلالها وجهات النظر على فئة ب.

تكمن المشكلة في أن هذه الآراء جزء من الصنف B وليست لدي أية فكرة عن الفئة (أ) ، لذا نحتاج إلى إيجاد طريقة للتواصل بين هاتين الفئتين ، وهذا هو المكان الذي يشرق فيه الوفد. قسمت التنفيذ إلى 6 خطوات حتى يمكنك استخدام هذا كصفيحة خداع عندما تحتاجها.

الخطوة 1: ابحث عن الخطوة 1 علامة pragma في ملف ClassBVC وقم بإضافة هذا

//MARK: step 1 Add Protocol here.
protocol ClassBVCDelegate: class {
func changeBackgroundColor(_ color: UIColor?)
}

الخطوة الأولى هي إنشاء protocol ، في هذه الحالة ، سنقوم بإنشاء البروتوكول في الفئة B ، داخل البروتوكول يمكنك إنشاء العديد من الوظائف التي تريدها استنادًا إلى متطلبات التنفيذ. في هذه الحالة ، لدينا فقط وظيفة بسيطة واحدة تقبل UIColor اختياري كوسيطة. هي ممارسة جيدة لتسمية البروتوكولات الخاصة بك بإضافة الكلمة delegate في نهاية اسم الفئة ، في هذه الحالة ، ClassBVCDelegate .

الخطوة 2: ابحث عن الخطوة 2 علامة pragma في ClassVBC وقم بإضافة هذا

//MARK: step 2 Create a delegate property here.
weak var delegate: ClassBVCDelegate?

هنا نقوم فقط بإنشاء خاصية تفويض للفئة ، يجب أن تعتمد هذه الخاصية نوع protocol ، ويجب أن تكون اختيارية. أيضا ، يجب عليك إضافة الكلمة المفتاحية الضعيفة قبل الخاصية لتفادي دورات الاحتفاظ و التسريبات المحتملة للذاكرة ، إذا كنت لا تعرف ما يعنيه ذلك ، فلا تقلق الآن ، فقط تذكر أن تضيف هذه الكلمة.

الخطوة 3: ابحث عن الخطوة 3 علامة pragma داخل method ClassBVC في ClassBVC وقم بإضافة هذا

//MARK: step 3 Add the delegate method call here.
delegate?.changeBackgroundColor(tapGesture.view?.backgroundColor)

شيء واحد يجب عليك معرفته ، تشغيل التطبيق والنقر على أي عرض ، لن ترى أي سلوك جديد وهذا صحيح ولكن الشيء الذي أريد أن أشير إليه هو أن التطبيق لا يتعطل عندما يتم استدعاء المندوب ، و لأننا نقوم بإنشائها كقيمة اختيارية ولهذا السبب لن تتعطل حتى المفوض غير موجود حتى الآن. دعونا الآن نذهب إلى ملف ClassAVC وجعله ، المفوض.

الخطوة 4: ابحث عن الخطوة 4 من علامة pragma داخل أسلوب ClassAVC في ClassAVC وأضف هذا بجانب نوع الفصل مثل هذا.

//MARK: step 4 conform the protocol here.
class ClassAVC: UIViewController, ClassBVCDelegate {
}

الآن اعتمد ClassBVCDelegate بروتوكول ClassBVCDelegate ، يمكنك أن ترى أن المجمع الخاص بك يعطيك خطأ يقول "النوع" ClassAVC لا يتوافق مع البروتوكول "ClassBVCDelegate" وهذا يعني أنك لم تستخدم أساليب البروتوكول حتى الآن ، تخيل أنه عندما يتبنى الصنف A البروتوكول ، فإنه يشبه توقيع عقد مع الفئة B ، وهذا العقد ينص على "يجب على أي صفي يعتمدني أن استخدم وظائفي!"

ملاحظة سريعة: إذا كنت قادمًا من خلفية Objective-C فمن المحتمل أنك تفكر في أنه يمكنك أيضًا إيقاف هذا الخطأ مما يجعل هذه الطريقة اختيارية ، ولكن لدهشتي ، وربما لغتك ، لا تدعم لغة Swift protocols الاختيارية ، إذا كنت تريد يمكنك إنشاء ملحق protocol الخاص بك أو استخدام الكلمةobjc في تنفيذ protocol الخاص بك.

شخصياً ، إذا كان لا بد لي من إنشاء بروتوكول بطرق اختيارية مختلفة ، فإنني أفضل تقسيمه إلى protocols مختلفة ، وبهذه الطريقة سأتبع مفهوم إعطاء مسؤولية واحدة إلى الأشياء الخاصة بي ، ولكن يمكن أن تختلف بناءً على التنفيذ المحدد.

هنا مقال جيد عن الطرق الاختيارية.

الخطوة 5: ابحث عن الخطوة 5 علامة pragma داخل التحضير لأسلوب segue وإضافة هذا

//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
}

هنا نحن نخلق مجرد مثال من ClassBVC وتعيين مندوبها لنفسها ، ولكن ماذا الذاتي هنا؟ حسنا ، النفس هي ClassAVC التي تم تفويضها!

الخطوة 6: أخيراً ، ابحث عن الخطوة 6 pragma في ClassAVC ودعنا نستخدم وظائف protocol ، ابدأ بكتابة تغيير funCackBackgroundColor وسترى أنه يقوم بإكماله تلقائيًا نيابة عنك. يمكنك إضافة أي تطبيق بداخله ، في هذا المثال ، سنقوم فقط بتغيير لون الخلفية ، إضافة هذا.

//MARK: step 6 finally use the method of the contract
func changeBackgroundColor(_ color: UIColor?) {
view.backgroundColor = color
}

الآن قم بتشغيل التطبيق!

Delegates موجودون في كل مكان ومن المحتمل أنك تستخدمهم دون إشعار مسبق ، إذا قمت بإنشاء عرض tableview في الماضي UIKIT التفويض ، UIKIT العديد من فئات UIKIT تعمل حولهم والعديد من frameworks الأخرى أيضا ، يحلون هذه المشاكل الرئيسية.

  • تجنب ضيق اقتران الأجسام.
  • تعديل السلوك والمظهر دون الحاجة إلى الكائنات فئة فرعية.
  • السماح بمعالجة المهام إلى أي كائن تعسفي.

تهانينا ، أنت مجرد تنفيذ مندوب مخصص ، وأنا أعلم أنك ربما يفكر ، الكثير من المتاعب لهذا فقط؟ حسنًا ، التفويض هو نمط تصميم مهم جدًا لفهم ما إذا كنت تريد أن تصبح مطورًا iOS ، ودائمًا ما تضع في اعتبارك أن لديها علاقة واحدة إلى علاقة بين الكائنات.

يمكنك رؤية البرنامج التعليمي الأصلي here


الإجراء عبارة عن مفوّض (مؤشر) إلى طريقة ، تأخذ الصفر ، معلمة إدخال واحدة أو أكثر ، ولكنها لا تعرض أي شيء.

Func هو المفوض (المؤشر) إلى أسلوب ، يأخذ صفر ، معلمة إدخال واحدة أو أكثر ، ويعيد قيمة (أو مرجع).

المسند هو نوع خاص من Func يستخدم في كثير من الأحيان لإجراء المقارنات.

على الرغم من استخدامها على نطاق واسع مع Linq ، تعتبر Action و Func مفاهيم منطقية مستقلة عن Linq. يحتوي C ++ بالفعل على المفهوم الأساسي في شكل مؤشرات دالة مكتوبة.

هنا مثال صغير للعمل و Func دون استخدام Linq:

class Program
{
    static void Main(string[] args)
    {
        Action<int> myAction = new Action<int>(DoSomething);
        myAction(123);           // Prints out "123"
                                 // can be also called as myAction.Invoke(123);

        Func<int, double> myFunc = new Func<int, double>(CalculateSomething);
        Console.WriteLine(myFunc(5));   // Prints out "2.5"
    }

    static void DoSomething(int i)
    {
        Console.WriteLine(i);
    }

    static double CalculateSomething(int i)
    {
        return (double)i/2;
    }
}






ios objective-c cocoa callback delegates