ডামিদের জন্য এনএসভুক্তি?


139

ঠিক কীভাবে NSInvocationকাজ করে? একটি ভাল পরিচয় আছে?

নিম্নলিখিত কোডটি ( ম্যাক ওএস এক্স, তৃতীয় সংস্করণের জন্য কোকো প্রোগ্রামিং থেকে) কীভাবে কাজ করে তা বোঝার ক্ষেত্রে আমি বিশেষভাবে সমস্যা বোধ করছি তবে তারপরেও টিউটোরিয়াল নমুনার স্বাধীনভাবে ধারণাগুলি প্রয়োগ করতে সক্ষম হব। কোড:

- (void)insertObject:(Person *)p inEmployeesAtIndex:(int)index
{
    NSLog(@"adding %@ to %@", p, employees);
    // Add inverse of this operation to undo stack
    NSUndoManager *undo = [self undoManager];
    [[undo prepareWithInvocationTarget:self] removeObjectFromEmployeesAtIndex:index];
    if (![undo isUndoing])
        [undo setActionName:@"Insert Person"];

    // Finally, add person to the array
    [employees insertObject:p atIndex:index];
}

- (void)removeObjectFromEmployeesAtIndex:(int)index
{
    Person *p = [employees objectAtIndex:index];
    NSLog(@"removing %@ from %@", p, employees);
    // Add inverse of this operation to undo stack
    NSUndoManager *undo = [self undoManager];
    [[undo prepareWithInvocationTarget:self] insertObject:p
                                       inEmployeesAtIndex:index];
    if (![undo isUndoing])
        [undo setActionName:@"Delete Person"];

    // Finally, remove person from array
    [employees removeObjectAtIndex:index];
}

এটি করার চেষ্টা করছে আমি পেয়েছি। (BTW, employeesএকটি হল NSArrayএকটি কাস্টম এর Personবর্গ।)

। নেট লোক হওয়ার কারণে আমি অপরিচিত ওবজে-সি এবং কোকো ধারণাগুলিকে মোটামুটি একই রকম। নেট ধারণাগুলিতে যুক্ত করার চেষ্টা করি। এটি নেট। এর প্রতিনিধি ধারণার মতো, তবে টাইপযুক্ত?

এটি বই থেকে 100% স্পষ্ট নয়, তাই আমি বাস্তব (কোষ) উদাহরণের নীচে মৌলিক ধারণাটি বুঝতে পেরে এমন লক্ষ্য নিয়ে আবারও বাস্তব কোকো / ওবজ-সি বিশেষজ্ঞদের কাছ থেকে পরিপূরক কিছু খুঁজছি। আমি সত্যই জ্ঞানটি স্বাধীনভাবে প্রয়োগ করতে সক্ষম হতে দেখছি - 9 ম অধ্যায় পর্যন্ত, আমার এটি করতে কোনও অসুবিধা হচ্ছিল না। কিন্তু এখন ...

আগাম ধন্যবাদ!

উত্তর:


284

মতে অ্যাপলের NSInvocation বর্গ রেফারেন্স :

একটি NSInvocationহ'ল একটি অবজেক্টিভ-সি বার্তাটি রেন্ডার করা স্ট্যাটিক, এটি হ'ল এটি একটি বস্তুতে রূপান্তরিত একটি ক্রিয়া।

এবং আরও কিছুটা বিশদে:

বার্তাগুলির ধারণাটি-সি-দর্শনের মূল বিষয়। যে কোনও সময় আপনি কোনও পদ্ধতিতে কল করুন বা কোনও বস্তুর ভেরিয়েবল অ্যাক্সেস করবেন, আপনি এটিকে একটি বার্তা প্রেরণ করছেন। NSInvocationআপনি যখন সময়ে কোনও ভিন্ন পয়েন্টে কোনও বস্তুর কাছে বার্তা পাঠাতে চান বা একই বার্তাটি বেশ কয়েকবার প্রেরণ করতে চান তখন কাজে আসে। NSInvocationআপনি করতে পারবেন বর্ণনা আপনি যে বার্তা পাঠাবেন করতে যাচ্ছি, এবং তারপর ডাকা এটি মধ্যে (আসলে লক্ষ্য বস্তু এটা পাঠান) পরে।


উদাহরণস্বরূপ, ধরুন আপনি অ্যারেতে একটি স্ট্রিং যুক্ত করতে চান। আপনি সাধারণত addObject:বার্তাটি নীচে পাঠাতেন :

[myArray addObject:myString];

এখন, ধরুন আপনি NSInvocationএই বার্তাটি সময় মতো অন্য কোনও সময়ে প্রেরণ করতে ব্যবহার করতে চান :

প্রথমত, আপনি এর নির্বাচকটির NSInvocationসাথে ব্যবহারের জন্য একটি সামগ্রী প্রস্তুত করবেন :NSMutableArrayaddObject:

NSMethodSignature * mySignature = [NSMutableArray
    instanceMethodSignatureForSelector:@selector(addObject:)];
NSInvocation * myInvocation = [NSInvocation
    invocationWithMethodSignature:mySignature];

এরপরে, আপনি কোন বিষয়টিকে বার্তা প্রেরণ করবেন তা নির্দিষ্ট করবেন:

[myInvocation setTarget:myArray];

আপনি যে বস্তুকে প্রেরণ করতে চান তা উল্লেখ করুন:

[myInvocation setSelector:@selector(addObject:)];

এবং এই পদ্ধতির জন্য কোনও যুক্তি পূরণ করুন:

[myInvocation setArgument:&myString atIndex:2];

নোট করুন যে অবজেক্ট আর্গুমেন্টগুলি অবশ্যই পয়েন্টার দিয়ে পাস করতে হবে। রায়ান ম্যাককুইগকে এটি নির্দেশ করার জন্য আপনাকে ধন্যবাদ এবং আরও তথ্যের জন্য দয়া করে অ্যাপলের ডকুমেন্টেশন দেখুন।

এই মুহুর্তে, myInvocationএকটি সম্পূর্ণ অবজেক্ট, প্রেরণ করা যেতে পারে এমন একটি বার্তা বর্ণনা করে। আসলে বার্তাটি প্রেরণ করতে, আপনি কল করবেন:

[myInvocation invoke];

এই চূড়ান্ত পদক্ষেপটি বার্তাকে প্রেরণে বাধ্যতামূলকভাবে কার্যকর করছে [myArray addObject:myString];

এটি ইমেল প্রেরণের মতো ভাবেন। আপনি একটি নতুন ইমেল ( NSInvocationঅবজেক্ট) খুলুন, আপনি যে ব্যক্তিকে (অবজেক্ট) পাঠাতে চান তার ঠিকানা পূরণ করুন, প্রাপকের জন্য একটি বার্তা টাইপ করুন (একটি selectorএবং আর্গুমেন্ট নির্দিষ্ট করুন ) এবং তারপরে "প্রেরণ" (কল করুন) ক্লিক করুন invoke)।

দেখুন NSInvocation ব্যবহার আরও তথ্যের জন্য। উপরের কাজ না করে এনএসআইভোকেশন ব্যবহার করে দেখুন ।


NSUndoManagerNSInvocationবস্তু ব্যবহার করে যাতে এটি আদেশগুলি বিপরীত করতে পারে । মূলত, আপনি যা করছেন তা NSInvocationবলার জন্য একটি অবজেক্ট তৈরি করছে : "আরে, আমি সবেমাত্র যা করেছি তা যদি আপনি পূর্বাবস্থায় ফিরিয়ে নিতে চান তবে এই যুক্তি সহ এই বার্তাটি সেই বস্তুর কাছে প্রেরণ করুন"। আপনি NSInvocationঅবজেক্টটি দিচ্ছেন NSUndoManager, এবং এটি সেই বস্তুকে যুক্ত করে নেওয়া যায় না এমন ক্রিয়াগুলির একটি অ্যারেতে। যদি ব্যবহারকারী "পূর্বাবস্থায় ফিরে যান" ডাকে, NSUndoManagerকেবল অ্যারের মধ্যে অতি সাম্প্রতিক ক্রিয়াটি সন্ধান করে এবং সঞ্চিত NSInvocationবস্তুকে প্রয়োজনীয় ক্রিয়া সম্পাদনের জন্য অনুরোধ করে।

আরও তথ্যের জন্য নিবন্ধগুলি পূর্বাবস্থায় ফেরান দেখুন See


10
অন্যথায় দুর্দান্ত উত্তরের একটি ছোটখাটো সংশোধন ... আপনাকে অবজেক্টগুলিতে একটি পয়েন্টার দিতে হবে setArgument:atIndex:, সুতরাং আরগ অ্যাসাইনমেন্টটি আসলে পড়তে হবে [myInvocation setArgument:&myString atIndex:2]
রায়ান ম্যাককুইগ

60
কেবল রায়ের নোট পরিষ্কার করতে, সূচক 0 "স্ব" এবং সূচক 1 "_ সিএমডি" এর জন্য সংরক্ষিত আছে (আরও বিশদে পোস্টের জন্য লিঙ্কটি দেখুন। জেমস লিঙ্কটি দেখুন)। সুতরাং আপনার প্রথম যুক্তি সূচী 2, সূচক 3 এ দ্বিতীয় যুক্তি ইত্যাদিতে স্থাপন করা হবে ...
ডেভ

4
@হরल्डক্যাম্পবেল: আমাদের কী ডাকতে হবে?
জেমস

6
আমরা সেটসিলেক্টরকে কেন কল করতে হবে তা আমি বুঝতে পারি না, যেহেতু আমরা ইতিমধ্যে মাই সিগনেচারে নির্বাচককে নির্দিষ্ট করেছি।
গ্লেনো

6
@ গ্লেনো: এনএসআইভোকেশন বেশ নমনীয়। আপনি আসলে কোনও সিলেক্টর সেট করতে পারেন যা মেথড সিগনেচারের সাথে মেলে, সুতরাং আপনাকে অগত্যা একই সিলেক্টরটি ব্যবহার করতে হবে না যা পদ্ধতি স্বাক্ষর তৈরি করতে ব্যবহৃত হয়েছিল। এই উদাহরণে, আপনি ঠিক সেটেলেক্টর: @ সিলেক্টর (রিলিজঅবজেক্ট :) করতে পারবেন, যেহেতু তারা একই পদ্ধতিতে স্বাক্ষর ভাগ করে।
জেমস

48

কার্যত এনএসআইভোকেশনের একটি সাধারণ উদাহরণ এখানে:

- (void)hello:(NSString *)hello world:(NSString *)world
{
    NSLog(@"%@ %@!", hello, world);

    NSMethodSignature *signature  = [self methodSignatureForSelector:_cmd];
    NSInvocation      *invocation = [NSInvocation invocationWithMethodSignature:signature];

    [invocation setTarget:self];                    // index 0 (hidden)
    [invocation setSelector:_cmd];                  // index 1 (hidden)
    [invocation setArgument:&hello atIndex:2];      // index 2
    [invocation setArgument:&world atIndex:3];      // index 3

    // NSTimer's always retain invocation arguments due to their firing delay. Release will occur when the timer invalidates itself.
    [NSTimer scheduledTimerWithTimeInterval:1 invocation:invocation repeats:NO];
}

যখন ডাকা হয় - [self hello:@"Hello" world:@"world"];- পদ্ধতিটি করবে:

  • "হ্যালো ওয়ার্ল্ড!" মুদ্রণ করুন
  • নিজের জন্য একটি এনএসমেথডসিগনেচার তৈরি করুন।
  • নিজেকে কল করে একটি এনএসআইভোকেশন তৈরি এবং পপুলেট করুন।
  • একটি এনএসটাইমারে এনএসআইভোকেশন পাস করুন
  • টাইমারটি (প্রায়) 1 সেকেন্ডে আগুন লাগবে, যার ফলে পদ্ধতিটিকে তার মূল যুক্তি দিয়ে আবার কল করা হবে।
  • পদ্ধতি পুনরাবৃত্তি করুন।

শেষ পর্যন্ত, আপনি এর মতো একটি প্রিন্টআউট পাবেন:

2010-07-11 17:48:45.262 Your App[2523:a0f] Hello world!
2010-07-11 17:48:46.266 Your App[2523:a0f] Hello world!
2010-07-11 17:48:47.266 Your App[2523:a0f] Hello world!
2010-07-11 17:48:48.267 Your App[2523:a0f] Hello world!
2010-07-11 17:48:49.268 Your App[2523:a0f] Hello world!
2010-07-11 17:48:50.268 Your App[2523:a0f] Hello world!
2010-07-11 17:48:51.269 Your App[2523:a0f] Hello world!
...

অবশ্যই, selfএনএসটাইমারের কাছে এটিতে এনএসইভোকেশন প্রেরণের জন্য লক্ষ্য অবজেক্টটি অবশ্যই অব্যাহত থাকবে। উদাহরণস্বরূপ, একটি সিঙ্গলটন অবজেক্ট বা অ্যাপ্লিকেশন যা অ্যাপ্লিকেশনের সময়কালের জন্য বিদ্যমান।


হালনাগাদ:

উপরে উল্লিখিত হিসাবে, আপনি কোনও এনএসটাইমারের পক্ষে আর্গুমেন্ট হিসাবে কোনও এনএসআইভোকশন পাস করার পরে, এনএসটিমোর স্বয়ংক্রিয়ভাবে এনএসআইভোকেশনের সমস্ত যুক্তি ধরে রাখে।

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

NSMethodSignature *signature  = ...;
NSInvocation      *invocation = [NSInvocation invocationWithMethodSignature:signature];
id                arg1        = ...;
id                arg2        = ...;

[invocation setTarget:...];
[invocation setSelector:...];
[invocation setArgument:&arg1 atIndex:2];
[invocation setArgument:&arg2 atIndex:3];

[invocation retainArguments];  // If you do not call this, arg1 and arg2 might be deallocated.

[self someMethodThatInvokesYourInvocationEventually:invocation];

6
এটি আকর্ষণীয় যে invocationWithMethodSignature:ইনিশিয়ালাইজারটি ব্যবহৃত হলেও , আপনাকে এখনও কল করতে হবে setSelector:। এটি অপ্রয়োজনীয় বলে মনে হচ্ছে, তবে আমি কেবল পরীক্ষা করেছি এবং এটি প্রয়োজনীয়।
থমাসডাব্লু

এটি কি অসীম লুপে চলতে থাকবে? এবং _সিএমডি কী
j2emanue


0

আমি এনএসআইএনভোকেশন সহ বিভিন্ন পদ্ধতি ধরণের কল করার একটি সহজ উদাহরণ তৈরি করি।

জেজ_এমএসজিএসেন্ড ব্যবহার করে আমার একাধিক প্যারাম কল করতে সমস্যা হয়েছিল

https://github.com/clearbrian/NSInvocation_Runtime

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