সবসময় এআরসি-তে ব্লকের মধ্যে স্ব-দুর্বল রেফারেন্সটি পাস করবেন?


252

অবজেক্টিভ-সি-তে ব্লক ব্যবহার সম্পর্কে আমি কিছুটা বিভ্রান্ত। আমি বর্তমানে এআরসি ব্যবহার করি এবং আমার অ্যাপটিতে আমার প্রচুর ব্লক রয়েছে, বর্তমানে সবসময় selfএর দুর্বল উল্লেখের পরিবর্তে উল্লেখ করা হয়। এটি কি এই ব্লকগুলি বজায় রাখা selfএবং এটিকে নিষ্পত্তি থেকে বিরত রাখার কারণ হতে পারে ? প্রশ্নটি হল, আমি কি সবসময় কোনও ব্লকের একটি weakরেফারেন্স ব্যবহার করব self?

-(void)handleNewerData:(NSArray *)arr
{
    ProcessOperation *operation =
    [[ProcessOperation alloc] initWithDataToProcess:arr
                                         completion:^(NSMutableArray *rows) {
        dispatch_async(dispatch_get_main_queue(), ^{
            [self updateFeed:arr rows:rows];
        });
    }];
    [dataProcessQueue addOperation:operation];
}

ProcessOperation.h

@interface ProcessOperation : NSOperation
{
    NSMutableArray *dataArr;
    NSMutableArray *rowHeightsArr;
    void (^callback)(NSMutableArray *rows);
}

ProcessOperation.m

-(id)initWithDataToProcess:(NSArray *)data completion:(void (^)(NSMutableArray *rows))cb{

    if(self =[super init]){
        dataArr = [NSMutableArray arrayWithArray:data];
        rowHeightsArr = [NSMutableArray new];
        callback = cb;
    }
    return self;
}

- (void)main {
    @autoreleasepool {
        ...
        callback(rowHeightsArr);
    }
}

আপনি যদি এই বিষয়ে গভীরতর বক্তৃতা চান dhoerl.wordpress.com/2013/04/23/… পড়ুন
ডেভিড এইচ

উত্তর:


721

এটি আলোচনার অংশ strongবা weakঅংশের দিকে মনোনিবেশ না করতে সহায়তা করে । পরিবর্তে চক্র অংশ উপর ফোকাস ।

অব্যাহত চক্রটি এমন একটি লুপ যা ঘটায় যখন বস্তু এ অবজেক্ট বি ধরে রাখে , এবং অবজেক্ট বি অবজেক্ট এটিকে ধরে রাখে সেই পরিস্থিতিতে, যদি উভয় বস্তু প্রকাশিত হয়:

  • অবজেক্ট এ এটিকে বাতিল করা হবে না কারণ অবজেক্ট বি এর একটি রেফারেন্স ধরে রেখেছে।
  • তবে অবজেক্ট বি যতক্ষণ অবজেক্ট এ এর ​​রেফারেন্স থাকে ততক্ষণ অবমুক্ত করা হবে না।
  • তবে অবজেক্ট এ কখনই বিলোপযুক্ত হবে না কারণ অবজেক্ট বি এর সাথে একটি উল্লেখ রেখেছে।
  • সীমাহীনভাবে

সুতরাং, এই দুটি বস্তু প্রোগ্রামের জীবনের স্মৃতিতে কেবল স্থির থাকবে যদিও তাদের উচিত যদি সবকিছু ঠিকঠাকভাবে কাজ করছিল তবে অবনমিত হও।

সুতরাং, আমরা যা সম্পর্কে উদ্বিগ্ন তা হ'ল চক্র ধরে রাখা , এবং এই চক্রগুলি তৈরি করে এবং নিজের মধ্যে বাধা সম্পর্কে কিছু নেই। এটি কোনও সমস্যা নয়, উদাহরণস্বরূপ:

[myArray enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop){
   [self doSomethingWithObject:obj];
}];

ব্লকটি ধরে রাখে self, তবে ব্লকটি ধরে রাখে selfনা। যদি একটি বা অন্যটি প্রকাশিত হয় তবে কোনও চক্র তৈরি হয় না এবং সবকিছু যেমনটি করা উচিত তেমনি হ্রাস পায়।

আপনি যেখানে সমস্যার মধ্যে পড়েন তা হ'ল:

//In the interface:
@property (strong) void(^myBlock)(id obj, NSUInteger idx, BOOL *stop);

//In the implementation:
[self setMyBlock:^(id obj, NSUInteger idx, BOOL *stop) {
  [self doSomethingWithObj:obj];     
}];

এখন, আপনার অবজেক্টের ( self) strongব্লকের একটি স্পষ্ট উল্লেখ রয়েছে। এবং ব্লকের একটি অন্তর্নিহিত দৃ strong রেফারেন্স রয়েছে self। এটি একটি চক্র, এবং এখন কোনওটিই সঠিকভাবে বিযুক্ত হবে না।

কারণ, এরকম পরিস্থিতিতে, self সংজ্ঞায় ইতিমধ্যে strongব্লকের একটি রেফারেন্স রয়েছে , selfব্লকটি ব্যবহারের জন্য স্পষ্টভাবে দুর্বল রেফারেন্স দিয়ে সমাধান করা সাধারণত সমাধান করা সহজ :

__weak MyObject *weakSelf = self;
[self setMyBlock:^(id obj, NSUInteger idx, BOOL *stop) {
  [weakSelf doSomethingWithObj:obj];     
}];

তবে যে কলগুলি ব্লকগুলি ব্যবহার করার সময় এটি অনুসরণ করা ডিফল্ট প্যাটার্নটি হওয়া উচিত নয়self ! এটি কেবল তখনই ভাঙ্গতে ব্যবহৃত হবে যা অন্যথায় স্ব এবং ব্লকের মধ্যে রক্ষণ চক্র হতে পারে। আপনি যদি এই প্যাটার্নটি সর্বত্রই অবলম্বন করতে চান তবে আপনি selfনির্বিঘ্নিত হওয়ার পরে মৃত্যুর পরে কার্যকর হওয়া কোনও কিছুতে ব্লক পাস করার ঝুঁকিটি চালিয়ে যাবেন ।

//SUSPICIOUS EXAMPLE:
__weak MyObject *weakSelf = self;
[[SomeOtherObject alloc] initWithCompletion:^{
  //By the time this gets called, "weakSelf" might be nil because it's not retained!
  [weakSelf doSomething];
}];

2
আমি নিশ্চিত নই যে এটিকে ধরে রাখি বি, বি ধরে রাখি একটি অসীম চক্র করবে। রেফারেন্স গণনার দৃষ্টিকোণ থেকে, এ এবং বি এর রেফারেন্স গণনাটি ১। এই পরিস্থিতিতে পরিস্থিতি ধরে রাখার কারণ যখন অন্য কোনও গোষ্ঠীর বাইরে এ এবং বি এর দৃ strong় উল্লেখ না থাকে - এর অর্থ আমরা এই দুটি বস্তুর কাছে পৌঁছাতে পারি না (আমরা বি কে ছেড়ে দিতে এবং এর বিপরীতে এটিকে নিয়ন্ত্রণ করতে পারে না), এরপরে, এ এবং বি উভয়কেই বাঁচিয়ে রাখার জন্য একে অপরকে রেফারেন্স করে।
ড্যানইউন লিউ

@Danyun যদিও এটা সত্যি যে একটি মধ্যবর্তী চক্র ধরে রাখা এবং B নয় অপুনরুদ্ধারযোগ্য পর্যন্ত এই বস্তু অন্য সমস্ত রেফারেন্স মুক্তি দেয়া হয়েছে এটি কোন কম একটি চক্র দেখা যায় না। বিপরীতভাবে, কারণ একটি নির্দিষ্ট চক্রটি পুনরুদ্ধারযোগ্য হতে পারে তার অর্থ এটি আপনার কোডটিতে রাখা ঠিক নয়। পুনরুদ্ধার চক্রগুলি খারাপ ডিজাইনের গন্ধ।
জেমমনস

@ জিমন্স হ্যাঁ, আমাদের যথাসাধ্য একটি রক্ষণশীল চক্রের নকশা এড়ানো উচিত।
ড্যানইউন লিউ

1
@ মাস্টার এটি আমার পক্ষে বলা অসম্ভব। এটি সম্পূর্ণভাবে আপনার -setCompleteionBlockWithSuccess:failure:পদ্ধতির বাস্তবায়নের উপর নির্ভর করে । তবে যদি paginatorমালিকানাধীন থাকে ViewControllerএবং এই ব্লকগুলি প্রকাশ না হওয়ার পরে কল না পাওয়া যায় ViewControllerতবে একটি __weakরেফারেন্স ব্যবহার করা নিরাপদ পদক্ষেপ হবে (কারণ selfব্লকের মালিকানাধীন জিনিসটির মালিকানা রয়েছে, এবং ব্লকগুলি যখন কল করে তখনও প্রায় আশেপাশে থাকতে পারে যদিও তারা এটি ধরে রাখে না)। তবে এটি অনেকটা "যদি" এস। এটি আসলে কী করবে তার উপর নির্ভর করে।
জিম্মন

1
@ জাই না, এবং এটি ব্লক / ক্লোজারগুলির সাথে মেমরি পরিচালনার সমস্যার কেন্দ্রস্থল। যখন কিছুই তাদের মালিক না হয় তখন অবজেক্টগুলি ডিলেকোসেট হয়ে যায়। MyObjectএবং SomeOtherObjectউভয়ই ব্লকের মালিক। কিন্তু কারণ ব্লক এর রেফারেন্স ফিরে MyObjectহয় weak, ব্লক না নিজের MyObject। সুতরাং ব্লকটি যতক্ষণ না হয় MyObject বা SomeOtherObject অস্তিত্বের অস্তিত্বের গ্যারান্টিযুক্ত MyObjectরয়েছে ততক্ষণ ব্লকের মতো কোনও গ্যারান্টি থাকবে না। MyObjectসম্পূর্ণরূপে বিলোপযুক্ত হতে পারে এবং যতক্ষণ না SomeOtherObjectএখনও বিদ্যমান রয়েছে ততক্ষণ ব্লকটি সেখানে থাকবে।
জেমনস

26

আপনাকে সর্বদা দুর্বল রেফারেন্স ব্যবহার করতে হবে না। যদি আপনার ব্লকটি ধরে না রাখা হয় তবে কার্যকর করা হয় এবং পরে তা বাতিল করা হয় তবে আপনি দৃ strongly়তার সাথে নিজেকে ক্যাপচার করতে পারেন, কারণ এটি কোনও ধরে রাখার চক্র তৈরি করবে না। কিছু ক্ষেত্রে, আপনি এমনকি ব্লকটি সম্পূর্ণ না হওয়া অবধি ব্লকটি ধরে রাখতে চান যাতে এটি অকাল হ্রাস না করে। তবে, আপনি যদি ব্লকটি দৃ strongly়ভাবে ক্যাপচার করেন এবং ভিতরে ক্যাপচার করেন তবে এটি একটি ধরে রাখার চক্র তৈরি করবে।


ঠিক আছে আমি কেবল একটি কলব্যাক হিসাবে ব্লকটি কার্যকর করি এবং আমি চাই না যে নিজেকে কোনওভাবেই ডিলোস করা হবে। তবে দেখে মনে হচ্ছে যেন আমি ধরে রাখার চক্র তৈরি করছিলাম কারণ প্রশ্নে ভিউ কন্ট্রোলার চুক্তি হয় না ...
the_ ক্রিটিক

1
উদাহরণস্বরূপ, যদি আপনার কাছে বার বোতাম আইটেম থাকে যা ভিউ কন্ট্রোলার দ্বারা ধরে রাখা হয় এবং আপনি সেই ব্লকে নিজেকে দৃ strongly়ভাবে ক্যাপচার করেন তবে একটি রক্ষণাবেক্ষণ চক্র থাকবে।
লিও নাটান

1
@MartinE। কোড স্যাম্পল সহ আপনার প্রশ্নটি আপডেট করা উচিত। লিও বেশ সঠিক (+1), এটি অগত্যা শক্তিশালী রেফারেন্স চক্র সৃষ্টি করে না তবে আপনি কীভাবে এই ব্লকগুলি ব্যবহার করেন তার উপর নির্ভর করে এটি হতে পারে। আপনি কোড স্নিপেট সরবরাহ করলে আমাদের পক্ষে সহায়তা করা আমাদের পক্ষে সহজ হবে।
রব

@ লিওনাটান আমি ধরে রাখার চক্রের ধারণাটি বুঝতে পেরেছি, তবে ব্লকগুলিতে কী ঘটে যায় তা সম্পর্কে আমি নিশ্চিত নই, যাতে আমাকে কিছুটা বিভ্রান্ত করে
The_critic

উপরের কোডে, অপারেশন শেষ হয়ে গেলে এবং ব্লকটি প্রকাশিত হয়ে গেলে আপনার স্ব-দৃষ্টান্তটি প্রকাশিত হবে। আপনার কীভাবে ব্লকগুলি কাজ করে এবং কখন এবং কখন তাদের সুযোগগুলিতে ক্যাপচার করে তা আপনার পড়া উচিত।
লিও নাটান

26

আমি @ জিমনের সাথে পুরোপুরি একমত:

তবে যে কলগুলি স্ব কল করে তাদের সাথে ডিল করার সময় আপনি যে ডিফল্ট প্যাটার্নটি অনুসরণ করবেন তা হ'ল না! এটি কেবল তখনই ভাঙ্গতে ব্যবহৃত হবে যা অন্যথায় স্ব এবং ব্লকের মধ্যে রক্ষণ চক্র হতে পারে। আপনি যদি এই প্যাটার্নটি সর্বত্রই অবলম্বন করতে চান তবে আপনি নিজেকে অচল করে দেওয়ার পরে মৃত্যুদন্ড কার্যকর করা এমন কিছুতে ব্লক পাস করার ঝুঁকিটি চালিয়ে যাবেন।

//SUSPICIOUS EXAMPLE:
__weak MyObject *weakSelf = self;
[[SomeOtherObject alloc] initWithCompletion:^{
  //By the time this gets called, "weakSelf" might be nil because it's not  retained!
  [weakSelf doSomething];
}];

এই সমস্যাটি কাটিয়ে উঠতে weakSelfব্লকের অভ্যন্তরে একটি শক্তিশালী রেফারেন্স সংজ্ঞায়িত করা যায়:

__weak MyObject *weakSelf = self;
[[SomeOtherObject alloc] initWithCompletion:^{
  MyObject *strongSelf = weakSelf;
  [strongSelf doSomething];
}];

3
দুর্বল সেলফের জন্য রেফারেন্স গণনাটি কি শক্তিশালী হবে না? এইভাবে একটি রক্ষণ চক্র তৈরি?
এমএসকেডাব্লু

12
চক্র পুনরুদ্ধার কেবলমাত্র যদি তারা অবজেক্টের স্থিতিশীল অবস্থায় থাকে তবে তা গুরুত্বপূর্ণ। কোডটি কার্যকর করছে এবং এর রাজ্যটি প্রবাহিত অবস্থায় রয়েছে, একাধিক এবং সম্ভবত অপ্রয়োজনীয় রক্ষণাবেক্ষণগুলি ভাল। যাইহোক, এই নিদর্শন সম্পর্কিত, একটি শক্তিশালী রেফারেন্স ক্যাপচার এটি ব্লক চালানোর আগে স্ব-ক্ষয় হয়ে যাওয়ার ক্ষেত্রে কিছুই করে না, এটি এখনও ঘটতে পারে। এটি নিশ্চিত করে যে ব্লকটি সম্পাদন করার সময় স্ব স্বরূপে বিভ্রান্ত না হয় । ব্লক যদি অ্যাসিঙ্ক অপারেশন করে তবে এটি হয়ে যাওয়ার জন্য একটি উইন্ডো দেয় This
পিয়ের হিউস্টন

@ স্মলডাডক, আপনার ব্যাখ্যাটি দুর্দান্ত। এখন আমি এই আরও ভাল বুঝতে। বই এটি কভার করা হয়নি, ধন্যবাদ।
হুবিন জাং

5
এটি স্ট্রংসেল্ফের একটি ভাল উদাহরণ নয়, কারণ স্ট্রংসেলফের স্পষ্ট সংযোজন হ'ল রানটাইম যেভাবেই চলবে: ডসোমথিং লাইনে, পদ্ধতি কলটির সময়কালের জন্য একটি শক্তিশালী রেফারেন্স নেওয়া হয়। যদি দুর্বল সেলফ ইতিমধ্যে অবৈধ হয়ে থাকে, তবে শক্তিশালী রেফ শূন্য হয় এবং পদ্ধতি কলটি কোনও অপ-অফ। স্ট্রংসেল্ফ হ'ল যদি আপনার ক্রমবর্ধমান ক্রিয়াকলাপ হয় বা কোনও সদস্য ক্ষেত্র ( ->) ব্যবহার করা থাকে তবে আপনি গ্যারান্টি দিতে চান যে আপনি আসলে একটি বৈধ রেফারেন্স পেয়েছেন এবং ক্রিয়াকলাপের পুরো সেট জুড়ে অবিচ্ছিন্নভাবে ধরে রাখেন, যেমনif ( strongSelf ) { /* several operations */ }
ইথান

19

লিও উল্লেখ করেছেন যে আপনি আপনার প্রশ্নের সাথে যুক্ত কোডটি একটি শক্তিশালী রেফারেন্স চক্র (ওরফে, চক্র ধরে রাখার) প্রস্তাব দেয় না। অপারেশন সম্পর্কিত একটি সমস্যা যা শক্তিশালী রেফারেন্স চক্রের কারণ হতে পারে যদি অপারেশনটি মুক্তি না পাওয়া যায়। যদিও আপনার কোড স্নিপেট পরামর্শ দেয় যে আপনি নিজের অপারেশনটিকে সমবর্তী হিসাবে সংজ্ঞায়িত করেননি, তবে আপনার যদি থাকে তবে এটি প্রকাশ করা হবে না যদি আপনি কখনই পোস্ট করেন না isFinished, বা যদি আপনার বিজ্ঞপ্তি নির্ভরতা বা এরকম কিছু থাকে। এবং যদি অপারেশনটি প্রকাশ না করা হয়, তবে ভিউ কন্ট্রোলারটি ছাড়া হয় না। আমি একটি ব্রেকপয়েন্ট বা NSLogআপনার ক্রিয়াকলাপের deallocপদ্ধতিতে যুক্ত করার পরামর্শ দেব এবং নিশ্চিত হয়েছি যে এটি কল হচ্ছে।

তুমি বলেছিলে:

আমি ধরে রাখার চক্রের ধারণাটি বুঝতে পেরেছি, তবে ব্লকগুলিতে কী ঘটেছিল তা আমি পুরোপুরি নিশ্চিত নই, যাতে আমাকে কিছুটা বিভ্রান্ত করে

ব্লকগুলির সাথে ঘটে যাওয়া ধরে রাখার চক্র (শক্তিশালী রেফারেন্স চক্র) সমস্যাগুলি ঠিক যেমন আপনি চেনেন সেইগুলি ধরে রাখার চক্র সম্পর্কিত সমস্যার মতো। একটি ব্লক ব্লকের মধ্যে উপস্থিত যে কোনও অবজেক্টের শক্তিশালী রেফারেন্স বজায় রাখবে এবং ব্লকটি প্রকাশ না হওয়া পর্যন্ত এটি শক্তিশালী রেফারেন্স প্রকাশ করবে না। সুতরাং, যদি ব্লক রেফারেন্সগুলি self, বা এমনকি কেবলমাত্র একটি উদাহরণের পরিবর্তনশীল selfউল্লেখ করা যায়, যা নিজের প্রতি দৃ strong় রেফারেন্স বজায় রাখে, ব্লকটি প্রকাশ না হওয়া অবধি সমাধান করা হয় না (বা এই ক্ষেত্রে NSOperationসাবক্লাসটি প্রকাশ না হওয়া অবধি) ।

আরও তথ্যের জন্য, প্রোগ্রামিংয়ের উদ্দেশ্য বিভাগ-সি- এর স্ব- বিভাগ ক্যাপচার করার সময় শক্তিশালী রেফারেন্স চক্র এড়িয়ে চলুন দেখুন : ব্লক দস্তাবেজ সহ কাজ করা

যদি আপনার ভিউ কন্ট্রোলারটি এখনও মুক্তি পাচ্ছে না, তবে আপনাকে কেবল সনাক্ত করতে হবে যে অমীমাংসিত শক্তিশালী রেফারেন্সটি কোথায় রয়েছে (ধরে নিলেন যে আপনি নিশ্চিত করেছেন যে NSOperationএটি বিলোপযুক্ত হচ্ছে)। একটি সাধারণ উদাহরণ হ'ল পুনরাবৃত্তি ব্যবহার NSTimer। অথবা কিছু কাস্টম delegateবা অন্যান্য অবজেক্ট যা ভুলভাবে একটি strongরেফারেন্স বজায় রেখেছে । আপনি প্রায়শই যেখানে জিনিসগুলি তাদের শক্তিশালী রেফারেন্স পাচ্ছে তা ট্র্যাক করার জন্য যন্ত্রপাতি ব্যবহার করতে পারেন, যেমন:

এক্সকোড 6 এ রেকর্ড রেফারেন্স গণনা

বা এক্সকোড 5 এ:

এক্সকোড 5 এ রেকর্ড রেফারেন্স গণনা


1
অপরটি উদাহরণটি হ'ল যদি ব্লক স্রষ্টায় অপারেশন ধরে রাখা হয় এবং এটি শেষ হয়ে গেলে তা প্রকাশ না করে। +1 সুন্দর লিখতে!
লিও নাটান

@ লিওনাটান সম্মত হয়েছেন, যদিও কোড স্নিপেট এটিকে স্থানীয় ভেরিয়েবল হিসাবে উপস্থাপন করে যা যদি তিনি এআরসি ব্যবহার করে তবে প্রকাশিত হবে। তবে আপনি ঠিক বলেছেন!
রব

1
হ্যাঁ, আমি কেবল একটি উদাহরণ দিচ্ছিলাম, যেমন অন্য উত্তরে ওপি অনুরোধ করেছিল।
লিও নাটান

যাইহোক, এক্সকোড 8 এ "ডিবাগ মেমরি গ্রাফ" রয়েছে, যা প্রকাশিত হয়নি এমন অবজেক্টের শক্তিশালী উল্লেখ খুঁজে পাওয়ার আরও সহজ উপায়। স্ট্যাকওভারফ্লো / প্রশ্নগুলি / 30992338/ … দেখুন ।
রব

0

কিছু ব্যাখ্যা ধরে রাখার চক্র সম্পর্কে একটি শর্তকে উপেক্ষা করে [যদি কোনও গ্রুপের দৃ relationships় সম্পর্কের একটি বৃত্ত দ্বারা সংযুক্ত থাকে, তবে তারা একে অপরকে বাঁচিয়ে রাখে এমনকি গোষ্ঠীর বাইরে থেকে কোনও শক্তিশালী উল্লেখ না থাকলেও।] আরও তথ্যের জন্য, দস্তাবেজটি পড়ুন


-2

এভাবে আপনি ব্লকের অভ্যন্তরে স্ব ব্যবহার করতে পারেন:

// ব্লকের কলিং

 NSString *returnedText= checkIfOutsideMethodIsCalled(self);

NSString* (^checkIfOutsideMethodIsCalled)(*)=^NSString*(id obj)
{
             [obj MethodNameYouWantToCall]; // this is how it will call the object 
            return @"Called";


};
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.