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



8 Answers

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

يجب أن يبدو الملف 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!");
}
Question

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

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




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

يجب إعلان البروتوكول على النحو التالي:

@protocol ServiceResponceDelegate <NSObject>

- (void) serviceDidFailWithRequestType:(NSString*)error;
- (void) serviceDidFinishedSucessfully:(NSString*)success;

@end

هذه هي فئة الخدمة التي ينبغي أن يتم فيها تنفيذ بعض المهام. يوضح كيفية تعريف المفوض وكيفية تعيين المفوض. في فئة التنفيذ بعد اكتمال المهمة يتم استدعاء الأساليب في المفوض.

@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

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

@interface viewController: UIViewController <ServiceResponceDelegate>
{
ServiceClass* _service;
}

- (void) go;

@end

@implementation viewController

//
//some methods
//

- (void) go
{
_service = [[ServiceClass alloc] init];
[_service setDelegate:self];
[_service someTask];
}

هذا كل شيء ، وبتنفيذ طرق التفويض في هذه الفئة ، سيعود التحكم بمجرد انتهاء العملية / المهمة.




إخلاء المسؤولية: هذا هو إصدار 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




نسخة سويفت

المندوب هو مجرد فصل يقوم ببعض الأعمال لفصل آخر. اقرأ التعليمات البرمجية التالية لمثال 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 .




كممارسة جيدة أوصت بها شركة 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 إذا كان العرض (المتوافق مع المفوض) قد نفذ بالفعل طريقة (طرق) اختيارك الخاصة بك أم لا.




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

إذا كنت قادماً من وجهة نظر 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 الخاصة بك.




Let's start with an example , if we buy a product online ,it goes through process like shipping/delivery handled by different teams.So if shipping gets completed ,shipping team should notify delivery team & it should be one to one communication as broadcasting this information would be overhead for other people / vendor might want to pass this information only to required people.

So if we think in terms of our app, an event can be an online order & different teams can be like multiple views.

هنا هو رمز تعتبر ShippingView باسم فريق الشحن و DeliveryView كفريق التسليم:

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



//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" ، العلامة)؛

}




يتيح لك القول بأن لديك فئة قمت بتطويرها وتريد إعلان خاصية مفوض لكي تتمكن من إعلامها عند حدوث بعض الأحداث:

@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

بحيث تقوم بتعريف بروتوكول في ملف رأس MyClass (أو ملف رأس منفصل) ، وتعلن عن معالجات الأحداث المطلوبة / الاختيارية التي يجب / يجب على المفوض تنفيذها ، ثم تعلن خاصية في MyClass من النوع ( id< MyClassDelegate> ) مما يعني أي الفئة c الموضوعية التي تتوافق مع البروتوكول MyClassDelegate ، ستلاحظ أن خاصية المفوض معلنة بأنها ضعيفة ، وهذا مهم جدًا لمنع دورة الاحتفاظ (غالبًا ما يحتفظ المفوض بمثيل MyClass لذا إذا قمت بإعلان المفوض كإبقاء ، كلاهما منهم سيحتفظ بعضهم البعض ولن يتم إطلاق سراح أي منهم).

ستلاحظ أيضًا أن طرق البروتوكول تمر مثيل MyClass إلى المفوض كمعلمة ، وهذا أفضل ممارسة في حالة رغبة المفوض في استدعاء بعض الأساليب على مثيل MyClass ويساعد أيضًا عند قيام المفوض MyClassDelegate عن نفسه كـ MyClassDelegate إلى مثيلات MyClass متعددة ، مثل عندما يكون لديك مثيلات ViewController متعددة في ViewController الخاص بك ويعلن نفسه على أنه UITableViewDelegate إلى كل منهم.

وداخل MyClass الخاص بك ، يمكنك إخطار المفوض بالأحداث المعلنة كما يلي:

if([_delegate respondsToSelector:@selector(myClass: requiredEventHandlerWithParameter:)])
{
     [_delegate myClass:self requiredEventHandlerWithParameter:(ParamType*)param];
}

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




Related