سؤال

هل من الممكن أن يكون لديك كتل كخصائص باستخدام بناء جملة الخصائص القياسية؟

هل هناك أي تغييرات ل قوس?

هل كانت مفيدة؟

المحلول

@property (nonatomic, copy) void (^simpleBlock)(void);
@property (nonatomic, copy) BOOL (^blockWithParamter)(NSString *input);

إذا كنت ستكرر نفس الكتلة في عدة أماكن ، فاستخدم نوع def

typedef void(^MyCompletionBlock)(BOOL success, NSError *error);
@property (nonatomic) MyCompletionBlock completion;

نصائح أخرى

إليك مثال على كيفية تحقيق هذه المهمة:

#import <Foundation/Foundation.h>
typedef int (^IntBlock)();

@interface myobj : NSObject
{
    IntBlock compare;
}

@property(readwrite, copy) IntBlock compare;

@end

@implementation myobj

@synthesize compare;

- (void)dealloc 
{
   // need to release the block since the property was declared copy. (for heap
   // allocated blocks this prevents a potential leak, for compiler-optimized 
   // stack blocks it is a no-op)
   // Note that for ARC, this is unnecessary, as with all properties, the memory management is handled for you.
   [compare release];
   [super dealloc];
}
@end

int main () {
    @autoreleasepool {
        myobj *ob = [[myobj alloc] init];
        ob.compare = ^
        {
            return rand();
        };
        NSLog(@"%i", ob.compare());
        // if not ARC
        [ob release];
    }

    return 0;
}

الآن ، الشيء الوحيد الذي سيحتاج إلى التغيير إذا كنت بحاجة إلى تغيير نوع المقارنة هو typedef int (^IntBlock)(). إذا كنت بحاجة إلى تمرير كائنين عليه ، فقم بتغييره إلى هذا: typedef int (^IntBlock)(id, id), وتغيير الكتلة إلى:

^ (id obj1, id obj2)
{
    return rand();
};

آمل أن يساعد هذا.

تحرير 12 مارس 2012:

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

لمزيد من القراءة ، يرجى مراجعة هذا المستند:http://clang.llvm.org/docs/automaticreferenceCounting.html

لسويفت ، فقط استخدم الإغلاق: مثال.


في الهدف-C ،

property (نسخة) void (^dostuff) (void) ؛

بكل بساطة.

وثائق Apple ، تشرح هذه المشكلة تمامًا:

أبل دوكو.

في ملف .h:

// Here is a block as a property:
//
// Someone passes you a block. You "hold on to it",
// while you do other stuff. Later, you use the block.
//
// The property 'doStuff' will hold the incoming block.

@property (copy)void (^doStuff)(void);

// Here's a method in your class.
// When someone CALLS this method, they PASS IN a block of code,
// which they want to be performed after the method is finished.

-(void)doSomethingAndThenDoThis:(void(^)(void))pleaseDoMeLater;

// We will hold on to that block of code in "doStuff".

ها هو ملف .m الخاص بك:

 -(void)doSomethingAndThenDoThis:(void(^)(void))pleaseDoMeLater
    {
    // Regarding the incoming block of code, save it for later:
    self.doStuff = pleaseDoMeLater;

    // Now do other processing, which could follow various paths,
    // involve delays, and so on. Then after everything:
    [self _alldone];
    }

-(void)_alldone
    {
    NSLog(@"Processing finished, running the completion block.");
    // Here's how to run the block:
    if ( self.doStuff != nil )
       self.doStuff();
    }

احذر من رمز مثال خارج التاريخ.

مع الأنظمة الحديثة (2014) ، افعل ما يظهر هنا. هذا بسيط. آمل أن يساعد شخص ما. عيد ميلاد سعيد 2013!

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

@interface       ReusableClass : NSObject
@property (nonatomic,copy) CALayer*(^layerFromArray)(NSArray*);
@end

@implementation  ResusableClass
static  NSString const * privateScope = @"Touch my monkey.";

- (CALayer*(^)(NSArray*)) layerFromArray { 
     return ^CALayer*(NSArray* array){
        CALayer *returnLayer = CALayer.layer
        for (id thing in array) {
            [returnLayer doSomethingCrazy];
            [returnLayer setValue:privateScope
                         forKey:@"anticsAndShenanigans"];
        }
        return list;
    };
}
@end

سخيف؟ نعم. مفيد؟ الجحيم نعم. فيما يلي طريقة مختلفة "أكثر ذرية" لتعيين العقار .. وفئة مفيدة يبعث على السخرية ...

@interface      CALayoutDelegator : NSObject
@property (nonatomic,strong) void(^layoutBlock)(CALayer*);
@end

@implementation CALayoutDelegator
- (id) init { 
   return self = super.init ? 
         [self setLayoutBlock: ^(CALayer*layer){
          for (CALayer* sub in layer.sublayers)
            [sub someDefaultLayoutRoutine];
         }], self : nil;
}
- (void) layoutSublayersOfLayer:(CALayer*)layer {
   self.layoutBlock ? self.layoutBlock(layer) : nil;
}   
@end

يوضح هذا تعيين خاصية Block عبر الملحق (وإن كان داخل init ، وهي ممارسة زخرفة بشكل صحيح ..) مقابل آلية "getter" غير الذرية للمثال الأول. في كلتا الحالتين ... يمكن دائمًا كتابة تطبيقات "المتشددين" ، لكل حالة.. ل.

CALayoutDelegator *littleHelper = CALayoutDelegator.new;
littleHelper.layoutBlock = ^(CALayer*layer){
  [layer.sublayers do:^(id sub){ [sub somethingElseEntirely]; }];
};
someLayer.layoutManager = littleHelper;

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

typedef    void(^NSControlActionBlock)(NSControl*); 
@interface       NSControl            (ActionBlocks)
@property (copy) NSControlActionBlock  actionBlock;    @end
@implementation  NSControl            (ActionBlocks)

- (NSControlActionBlock) actionBlock { 
    // use the "getter" method's selector to store/retrieve the block!
    return  objc_getAssociatedObject(self, _cmd); 
} 
- (void) setActionBlock:(NSControlActionBlock)ab {

    objc_setAssociatedObject( // save (copy) the block associatively, as categories can't synthesize Ivars.
    self, @selector(actionBlock),ab ,OBJC_ASSOCIATION_COPY);
    self.target = self;                  // set self as target (where you call the block)
    self.action = @selector(doItYourself); // this is where it's called.
}
- (void) doItYourself {

    if (self.actionBlock && self.target == self) self.actionBlock(self);
}
@end

الآن ، عندما تقوم بتكوين زر ، ليس عليك إعداد بعض IBAction الدراما .. فقط ربط العمل الذي يتعين القيام به في الخلق ...

_button.actionBlock = ^(NSControl*thisButton){ 

     [doc open]; [thisButton setEnabled:NO]; 
};

يمكن تطبيق هذا النمط مرارا وتكر API الكاكاو. استخدم الخصائص لجلب الأجزاء ذات الصلة من الكود الخاص بك اقرب معا, ، القضاء نماذج التفويض المعقدة, ، والاستفادة من قوة الكائنات التي تتجاوز مجرد عمل "حاويات" غبية.

بالطبع يمكنك استخدام الكتل كخصائص. ولكن تأكد من إعلانها باسم property (نسخة). فمثلا:

typedef void(^TestBlock)(void);

@interface SecondViewController : UIViewController
@property (nonatomic, copy) TestBlock block;
@end

في MRC ، يتم تخصيص متغيرات السياق الكتل في كومة; ؛ سيتم إطلاقها عند تدمير إطار المكدس. إذا تم نسخها ، سيتم تخصيص كتلة جديدة كومة, ، والتي يمكن تنفيذها لاحقًا بعد أن يتم طرح إطار المكدس.

disclamer

هذا ليس المقصود أن يكون "الإجابة الجيدة" ، حيث أن هذا السؤال يطرح صراحة عن ObjectiveC. عندما قدمت Apple Swift في WWDC14 ، أود مشاركة الطرق المختلفة لاستخدام الكتلة (أو الإغلاق) في Swift.

مرحبا ، سويفت

لديك العديد من الطرق لتمرير كتلة مكافئة للعمل في Swift.

لقد وجدت ثلاثة.

لفهم هذا ، أقترح عليك اختبار هذه الكود الصغير في الملعب.

func test(function:String -> String) -> String
{
    return function("test")
}

func funcStyle(s:String) -> String
{
    return "FUNC__" + s + "__FUNC"
}
let resultFunc = test(funcStyle)

let blockStyle:(String) -> String = {s in return "BLOCK__" + s + "__BLOCK"}
let resultBlock = test(blockStyle)

let resultAnon = test({(s:String) -> String in return "ANON_" + s + "__ANON" })


println(resultFunc)
println(resultBlock)
println(resultAnon)

سريع ، محسّن للإغلاق

نظرًا لأنه تم تحسين Swift للتنمية غير المتزامنة ، عملت Apple بشكل أكبر على الإغلاق. الأول هو أنه يمكن استنتاج توقيع الوظيفة حتى لا تضطر إلى إعادة كتابته.

الوصول إلى المعلمات بالأرقام

let resultShortAnon = test({return "ANON_" + $0 + "__ANON" })

الاستدلال المعامل مع التسمية

let resultShortAnon2 = test({myParam in return "ANON_" + myParam + "__ANON" })

الإغلاق الزائد

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

فيما يلي مثال (تم دمجه مع توقيع مستنتج لإظهار السلطة السريعة)

let resultTrailingClosure = test { return "TRAILCLOS_" + $0 + "__TRAILCLOS" }

أخيراً:

استخدام كل هذه القوة ما سأفعله هو خلط الإغلاق الخلفي والاستدلال على النوع (مع تسمية لقدرة)

PFFacebookUtils.logInWithPermissions(permissions) {
    user, error in
    if (!user) {
        println("Uh oh. The user cancelled the Facebook login.")
    } else if (user.isNew) {
        println("User signed up and logged in through Facebook!")
    } else {
        println("User logged in through Facebook!")
    }
}

مرحبا ، سويفت

استكمال ما أجاب @francescu.

إضافة معلمات إضافية:

func test(function:String -> String, param1:String, param2:String) -> String
{
    return function("test"+param1 + param2)
}

func funcStyle(s:String) -> String
{
    return "FUNC__" + s + "__FUNC"
}
let resultFunc = test(funcStyle, "parameter 1", "parameter 2")

let blockStyle:(String) -> String = {s in return "BLOCK__" + s + "__BLOCK"}
let resultBlock = test(blockStyle, "parameter 1", "parameter 2")

let resultAnon = test({(s:String) -> String in return "ANON_" + s + "__ANON" }, "parameter 1", "parameter 2")


println(resultFunc)
println(resultBlock)
println(resultAnon)

يمكنك متابعة التنسيق أدناه ويمكنك استخدام testingObjectiveCBlock الممتلكات في الفصل.

typedef void (^testingObjectiveCBlock)(NSString *errorMsg);

@interface MyClass : NSObject
@property (nonatomic, strong) testingObjectiveCBlock testingObjectiveCBlock;
@end

لمزيد من المعلومات ، إلقاء نظرة هنا

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top