কীভাবে পারফেক্টসলেক্টরটি ব্যবহার করবেন: উইথ অবজেক্ট: আফটার ডেলি: কোকোতে আদিম ধরণের সাথে?


97

NSObjectপদ্ধতি performSelector:withObject:afterDelay:আমাকে একটা নির্দিষ্ট সময় পর একটি বস্তু আর্গুমেন্ট সহ বস্তুর উপর একটি পদ্ধতি ডাকা করতে পারবেন। এটি অ-অবজেক্ট আর্গুমেন্টের সাথে পদ্ধতির জন্য ব্যবহার করা যায় না (উদাঃ ইনটস, ফ্লোটস, স্ট্রাক্টস, নন-অবজেক্ট পয়েন্টার ইত্যাদি)।

অ-অবজেক্ট আর্গুমেন্ট সহ কোনও পদ্ধতিতে একই জিনিস অর্জনের সহজ উপায় কী ? আমি জানি যে নিয়মিত জন্য performSelector:withObject:, সমাধানটি ব্যবহার করা হয় NSInvocation(যা আসলেই জটিল)। তবে "বিলম্ব" অংশটি কীভাবে পরিচালনা করতে হয় তা আমি জানি না।

ধন্যবাদ,


এটি কিছুটা হ্যাকিশ তবে দ্রুত কোড লিখতে আমার পক্ষে এটি দরকারী মনে হয়েছে। এর মতো কিছু: আইডি অবজেক্ট = [অ্যারে পারফরম্যান্স নির্বাচনকারী: @ নির্বাচক (অবজেক্টআটিআইন্ডেক্স :) সহ অবজেক্ট: (__ ব্রিজ_টান্সফার) (শূন্য *) 1]; । যুক্তি যদি 0 হয় তবে আপনার একটি ব্রিজের castালাইও লাগবে না কারণ 0 "বিশেষ" এবং আইডি এটির সাথে সামঞ্জস্যপূর্ণ।
রামি আল জুহুরি

উত্তর:


72

এখানে আমি এনএসআইভোকেশন ব্যবহার করে কোনও পরিবর্তন করতে পারি না এমনটি বলেছিলাম:

SEL theSelector = NSSelectorFromString(@"setOrientation:animated:");
NSInvocation *anInvocation = [NSInvocation
            invocationWithMethodSignature:
            [MPMoviePlayerController instanceMethodSignatureForSelector:theSelector]];

[anInvocation setSelector:theSelector];
[anInvocation setTarget:theMovie];
UIInterfaceOrientation val = UIInterfaceOrientationPortrait;
BOOL anim = NO;
[anInvocation setArgument:&val atIndex:2];
[anInvocation setArgument:&anim atIndex:3];

[anInvocation performSelector:@selector(invoke) withObject:nil afterDelay:1];

কেন শুধু না [theMovie setOrientation: UIInterfaceOrientationPortrait animated:NO]? অথবা আপনি কী বোঝাতে চেয়েছেন যে invokeবার্তাটি আপনি যে পদ্ধতিতে-পরে-বিলম্ব সম্পাদন করেন?
পিটার হোসে

আহা হ্যাঁ, আমি বলতে ভুলে গেছি .. `[Iআনওয়কেশন পারফরম্যান্স সিলেক্টর: @ সিলেক্টর (ডাকে) ডেলিয়ার পরে: 0.5];
মর্তি

25
যারা জানেন না তাদের জন্য কেবল একটি পার্শ্ব নোট, আমরা সূচি 2 থেকে যুক্তি যুক্ত করা শুরু করি কারণ সূচক 0 এবং 1 গোপন যুক্তি "স্ব" এবং "_ সিএমডি" এর জন্য সংরক্ষিত।
বিশাল সিং

35

এনএসএন নাম্বারে কেবল ফ্লোট, বুলিয়ান, ইনট বা অনুরূপ জড়ান।

স্ট্রাক্টগুলির জন্য, আমি কোনও সহজ সমাধান সম্পর্কে জানি না, তবে আপনি একটি পৃথক ওবিজেসি ক্লাস তৈরি করতে পারেন যা এই জাতীয় কাঠামোর মালিক।


5
একটি মোড়কের পদ্ধতি তৈরি করুন, -ডিলেডমেথডওথআরগমেন্ট: (এনএসএনম্বার *) আরগ করুন। এনএসএনবার থেকে আদিমকে টেনে আনার পরে এটি মূল পদ্ধতিতে কল করুন।
জেমস উইলিয়ামস

4
বুঝেছি। তারপরে আমি মার্জিত সমাধানের বিষয়ে নিশ্চিত নই, তবে আপনি অন্য পদ্ধতিটি যুক্ত করতে পারেন যা আপনার সঞ্চালক নির্বাচিতের লক্ষ্য হিসাবে লক্ষ্য করা হয়েছে: যা এনএসএনবারকে আনপ্যাক করে এবং আপনার বর্তমানে যে পদ্ধতিটি মনে আছে সে সম্পর্কে চূড়ান্ত নির্বাচক সম্পাদন করে। আর একটি ধারণা যা আপনি অন্বেষণ করতে পারেন তা হ'ল এনএসবজেক্টে একটি বিভাগ তৈরি করা যা পারফর্মসেক্টর যুক্ত করে: ইনট: ... (এবং অনুরূপ)।
ক্ষতিগ্রস্ত

32
NSValue (NSNumber এর সুপারক্লাস) আপনি যা কিছু দেবেন তা মোড়ানো হবে। আপনি যদি 'বার' নামক 'স্ট্রাক্ট ফু' উদাহরণটি মোড়তে চান তবে আপনি '[এনএসভ্যালু মান উইথবাইটস: & বার অবজেক্টটাইপ: @ এনকোড (স্ট্রাক্ট foo)] করতে চান;'
জিম ডোভী

4
স্ট্রাক মোড়ানোর জন্য আপনি এনএসওয়ালু ব্যবহার করতে পারেন। যেভাবেই হোক, এনএসএনম্বার / এনএসভ্যালু হ'ল সঠিক সমাধান।
পিটার হোসি

6
নিশ্চিত হয়েছে: প্যারামিটারটি পাওয়ার জন্য পাস করা আবশ্যক ( )nilBOOLNOFALSE
নিকোলাস মিয়ারি

13

এই উত্তরটি ব্যবহার করবেন না। আমি কেবলমাত্র ISTতিহাসিক উদ্দেশ্যগুলির জন্য এটি বামে রেখেছি। নীচে মন্তব্যগুলি দেখুন।

এটি যদি কোনও BOOL প্যারামিটার হয় তবে একটি সহজ কৌশল আছে।

হ্যাঁ, না জন্য পাস এবং শিরোনাম। নিলের কোনও বিওএল মান নিক্ষেপ করা হয়। স্ব YES এর BOOL মানটিতে নিক্ষিপ্ত হয়

যদি এই কোনও BOOL প্যারামিটার ব্যতীত অন্য কিছু হয় তবে এই পদ্ধতির ভাঙ্গন ঘটে।

ধরে নেওয়া স্ব একটি ইউআইভিউ।

//nil will be cast to NO when the selector is performed
[self performSelector:@selector(setHidden:) withObject:nil afterDelay:5.0];

//self will be cast to YES when the selector is performed
[self performSelector:@selector(setHidden:) withObject:self afterDelay:10.0];

আমি বিশ্বাস করি যে BOOL এর মানগুলি সর্বদা 0 বা 1 হওয়া উচিত এটি সত্য যে বেশিরভাগ কোড পাত্তা দেয় না এবং if ()এটির জন্য কেবল একটি পরীক্ষা করবে, তবে এটি অনুমানযোগ্য যে কোনও কোড তার 0 বা 1 হওয়ার উপর নির্ভর করবে এবং এভাবে জিতেছে কিছু বড় ঠিকানা মান 1 (হ্যাঁ) এর সমান হিসাবে বিবেচনা করবেন না।
ব্যবহারকারী 102008

4
তার জন্য ধন্যবাদ, একটি মোড়ক তৈরি করতে বা এটি করতে কুৎসিত জিসিডি সিনট্যাক্স লিখতে চাইছিল না।
0xSina

10
এটি কোনওটিই ব্যবহার করবেন না । এই পদ্ধতির গুরুতর বাগগুলির উত্স, এটি খুঁজে পাওয়া শক্ত। selfমত ঠিকানা দিয়ে কল্পনা করুন 0x0123400। এই পদ্ধতির সাথে, আপনি 0.4% ক্ষেত্রে হ্যাঁ কোনও জাল পাবেন না । অধিকতর, এই সম্ভাবনার সাথে, এই সমাধানটি সমস্ত পরীক্ষায় পাস হতে পারে এবং পরে প্রকাশ করে।
ওলেগ ট্রাখম্যান

4
ইউপিডি: মেমরির প্রান্তিককরণের কারণে 6% প্রোবিলিটি দিয়ে কেউ ইয়েস নিরীক্ষণ করতে পারে না
ওলেগ ট্রাখমান


8

সম্ভবত এনএসভ্যালু , কেবল নিশ্চিত করুন যে আপনার পয়েন্টারগুলি এখনও বিলম্বের পরে বৈধ আছে ( উদা । স্ট্যাকের জন্য কোনও বস্তু বরাদ্দ নেই)।


কোনও পুরানো পদ্ধতি কি প্রত্যাশিতভাবে "আনবক্স" করবে NSValue(যদি সম্ভব হয়) type?
অ্যালেক্স গ্রে

8

আমি জানি এটি একটি পুরানো প্রশ্ন তবে আপনি যদি আইওএস এসডিকে 4+ তৈরি করে থাকেন তবে আপনি খুব অল্প প্রচেষ্টা করে ব্লকগুলি ব্যবহার করতে পারেন এবং এটিকে আরও পঠনযোগ্য করে তুলতে পারেন:

double delayInSeconds = 2.0;
int primitiveValue = 500;
dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delayInSeconds * NSEC_PER_SEC));
dispatch_after(popTime, dispatch_get_main_queue(), ^(void){
    [self doSomethingWithPrimitive:primitiveValue];     
});

এটি একটি ধরে রাখা লুপ তৈরি করে। এটি সঠিকভাবে কাজ করার জন্য আপনাকে নিজের বিষয়ে একটি দুর্বল রেফারেন্স তৈরি করতে হবে এবং নির্বাচকটি সম্পাদন করতে সেই উল্লেখটি ব্যবহার করতে হবে। "__ block টাইপ অফ (স্ব) দুর্বল সেলফ = স্ব;"
টিম ওয়াচটার

4
আপনার এখানে দুর্বল রেফারেন্সের দরকার নেই কারণ স্ব ব্লকটি ধরে রাখে না (কোনও রক্ষণ লুপ নেই)। কোনও শক্তিশালী রেফারেন্স ব্যবহার করা সম্ভবত নিজের থেকে ভাল, যেহেতু নিজেরাই অন্যথায় হ্রাস পেতে পারে। দেখুন: স্ট্যাকওভারফ্লো.com
সেবাস্তিয়ান মার্টিন

6

পারফর্মসিলিেক্টর: উইওবজেক্ট সর্বদা একটি অবজেক্ট নেয়, যাতে ইন / ডাবল / ফ্লোট ইত্যাদি যুক্তিগুলি পাস করার জন্য ..... আপনি এর মতো কিছু ব্যবহার করতে পারেন।

//NSNumber is an object..

    [self performSelector:@selector(setUserAlphaNumber:) withObject: [NSNumber numberWithFloat: 1.0f]
    afterDelay:1.5];

    -(void) setUserAlphaNumber: (NSNumber*) number{

     [txtUsername setAlpha: [number floatValue] ];
    }

একইভাবে আপনি [এনএসএন নাম্বারবিহীন আইটেম:] ইত্যাদি ব্যবহার করতে পারেন .... এবং প্রাপ্ত পদ্ধতিতে আপনি নম্বরটি [বিন্যাস] বা [সংখ্যা দ্বিগুণ] হিসাবে আপনার বিন্যাসে রূপান্তর করতে পারেন।


4
যদি কোনওটি + পারফরম্যান্সলেকটর: ওজেক্ট: সহ সীমাবদ্ধ থাকে তবে কেবলমাত্র আইএমও পোস্ট করা সঠিক উত্তর posted তবে ব্লকগুলি ব্যবহার করে @ মাইকেলগেলর্ডের উত্তর পরিষ্কার, যদি এটি আপনার পক্ষে একটি বিকল্প হয়।
big_m

5

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

[MONBlock performBlock:^{[obj setFrame:SOMETHING];} afterDelay:2];

ব্লকগুলি আপনাকে স্বেচ্ছাচারিত প্যারামিটার তালিকা, রেফারেন্স অবজেক্ট এবং ভেরিয়েবলগুলি ক্যাপচার করতে দেয়।

ব্যাকিং বাস্তবায়ন (বেসিক):

@interface MONBlock : NSObject

+ (void)performBlock:(void(^)())pBlock afterDelay:(NSTimeInterval)pDelay;

@end

@implementation MONBlock

+ (void)imp_performBlock:(void(^)())pBlock
{
 pBlock();
}

+ (void)performBlock:(void(^)())pBlock afterDelay:(NSTimeInterval)pDelay
{
  [self performSelector:@selector(imp_performBlock:)
             withObject:[pBlock copy]
             afterDelay:pDelay];
}

@end

উদাহরণ:

int main(int argc, const char * argv[])
{
 @autoreleasepool {
  __block bool didPrint = false;
  int pi = 3; // close enough =p

  [MONBlock performBlock:^{NSLog(@"Hello, World! pi is %i", pi); didPrint = true;} afterDelay:2];

  while (!didPrint) {
   [NSRunLoop.currentRunLoop runUntilDate:[NSDate dateWithTimeInterval:0.1 sinceDate:NSDate.date]];
  }

  NSLog(@"(Bye, World!)");
 }
 return 0;
}

অন্য উদাহরণের জন্য মাইকের উত্তর (+1) দেখুন।


3

আমি সর্বদা স্মরণ করিয়ে দেব যে আপনি NSMutableArray অবজেক্ট হিসাবে পাস করবেন। এটি কারণ আপনি তারপরে বোতাম টিপানো এবং অন্যান্য মানগুলির মতো কয়েকটি বস্তু পাস করতে পারেন। NSNumber, NSInteger এবং NSString কেবলমাত্র কিছু মূল্যের ধারক। নিশ্চিত হয়ে নিন যে অ্যারে থেকে যখন আপনি কোনও সঠিক ধারক প্রকারটি থেকে উল্লেখ করেছেন the আপনাকে এনএস পাত্রে পাস করতে হবে। সেখানে আপনি মান পরীক্ষা করতে পারেন। মনে রাখবেন যে মানগুলি তুলনা করা হয় তখন পাত্রে আইসকুয়াল ব্যবহার হয়।

#define DELAY_TIME 5

-(void)changePlayerGameOnes:(UIButton*)sender{
    NSNumber *nextPlayer = [NSNumber numberWithInt:[gdata.currentPlayer intValue]+1 ];
    NSMutableArray *array = [[NSMutableArray alloc]initWithObjects:sender, nil];
    [array addObject:nextPlayer];
    [self performSelector:@selector(next:) withObject:array afterDelay:DELAY_TIME];
}
-(void)next:(NSMutableArray*)nextPlayer{
    if(gdata != nil){ //if game choose next player
       [self nextPlayer:[nextPlayer objectAtIndex:1] button:[nextPlayer objectAtIndex:0]];
    }
}

2

আমি এটি করতেও চেয়েছিলাম, তবে একটি পদ্ধতি যা একটি বিওওএল প্যারামিটার গ্রহণ করে। এনএসএনম্বারের সাথে বুল মানটি মোড়ানো, ভ্যালুটি পাস করতে ব্যর্থ। কেন আমি জানি না।

সুতরাং আমি একটি সহজ হ্যাক করছেন শেষ। আমি প্রয়োজনীয় প্যারামিটারটি অন্য একটি ডামি ফাংশনে রেখেছি এবং সেই ফাংশনটি সঞ্চালনকারী নির্বাচন করে কল করি, যেখানে ওজেক্ট = শূন্য;

[self performSelector:@selector(dummyCaller:) withObject:nil afterDelay:5.0];

-(void)dummyCaller {

[self myFunction:YES];

}

ক্ষতির উত্তরের উপরে আমার মন্তব্যটি দেখুন। দেখে মনে হচ্ছে, যেহেতু -performSelector[...]পদ্ধতিটি কোনও বস্তুর প্রত্যাশা করে (কোনও প্রাথমিক তথ্য প্রকারের পরিবর্তে), এবং এটি জানে না যে নির্বাচিত নির্বাচকটি কোনও বুলিয়ান গ্রহণ করে, সম্ভবত NSNumberউদাহরণটির ঠিকানা (পয়েন্টার মান) অন্ধভাবে 'কাস্ট' থেকে BOOL(= শূন্য নয়, অর্থাত্ TRUE)। সম্ভবত রানটাইম এর চেয়ে বেশি স্মার্ট হতে পারে এবং একটিতে জড়ানো শূন্য বুলিয়ান চিনতে পারে NSNumber!
নিকোলাস মিয়ারি

আমি রাজী. আমি অনুমান করি যে আরও ভাল কাজটি হ'ল সম্পূর্ণভাবে BOOL এড়ানো এবং NO এর জন্য পূর্ণসংখ্যা 0 এবং হ্যাঁ এর জন্য 1 ব্যবহার করা এবং এটি NSNumber বা NSValue দিয়ে মোড়ানো।
জেনকোড

কিছু পরিবর্তন হয় না? যদি তা হয় তবে হঠাৎ করেই আমি কোকোতে সত্যই হতাশ হয়েছি :)
নিকোলাস ম্যারি

2

আমি দেখতে পেলাম যে এটি করার দ্রুততম (তবে কিছুটা নোংরা) উপায় হ'ল সরাসরিcc_msgSend পাঠানো। তবে এটি সরাসরি আবেদন করা বিপজ্জনক কারণ আপনার ডকুমেন্টেশনটি পড়তে হবে এবং নিশ্চিত হওয়া উচিত যে আপনি রিটার্ন মানটির ধরণের জন্য সঠিক বৈকল্পিকটি ব্যবহার করছেন এবং কারণ আবজেক_এমএসসেন্ডকে সংকলক সুবিধার জন্য ভার্গ হিসাবে সংজ্ঞায়িত করা হয়েছে তবে বাস্তবে দ্রুত সমাবেশ আঠালো হিসাবে প্রয়োগ করা হয়েছে । এখানে একটি প্রতিনিধি পদ্ধতি কল করতে কিছু কোড ব্যবহৃত হয় - [ডেলিগেট ইন্টিজারডিডিচঞ্জ:] যা একটি একক পূর্ণসংখ্যার যুক্তি নেয়।

#import <objc/message.h>


SEL theSelector = @selector(integerDidChange:);
if ([self.delegate respondsToSelector:theSelector])
{
    typedef void (*IntegerDidChangeFuncPtrType)(id, SEL, NSInteger);
    IntegerDidChangeFuncPtrType MyFunction = (IntegerDidChangeFuncPtrType)objc_msgSend;
    MyFunction(self.delegate, theSelector, theIntegerThatChanged);
}

এটি প্রথমে নির্বাচককে বাঁচায় যেহেতু আমরা এটির একাধিকবার উল্লেখ করব এবং টাইপ তৈরি করা সহজ হবে। এরপরে এটি যাচাই করে যে প্রতিনিধিটি নির্বাচককে আসলে প্রতিক্রিয়া জানায় - এটি একটি alচ্ছিক প্রোটোকল হতে পারে। এরপরে এটি একটি ফাংশন পয়েন্টার প্রকার তৈরি করে যা নির্বাচকের প্রকৃত স্বাক্ষর নির্দিষ্ট করে। মনে রাখবেন যে সমস্ত অবজেক্টিভ-সি বার্তাগুলিতে দুটি লুকানো প্রথম যুক্তি রয়েছে, বস্তুটি বার্তা দেওয়া হচ্ছে এবং নির্বাচককে পাঠানো হচ্ছে। তারপরে আমরা উপযুক্ত প্রকারের একটি ফাংশন পয়েন্টার তৈরি করি এবং এটিকে অন্তর্নিহিত অবজেক্ট_এমএসজি ফাংশনটিতে নির্দেশ করতে সেট করি। মনে রাখবেন যে যদি রিটার্ন মানটি একটি ভাসা বা কাঠামো হয় তবে আপনাকে objc_msgSend এর একটি ভিন্ন ধরণের ব্যবহার করতে হবে। অবশেষে, ওজেক্টিভ-সি শিটের নীচে যে একই যন্ত্রপাতি ব্যবহার করে বার্তাটি প্রেরণ করুন।


"মনে রাখবেন যে আপনি যদি ফ্লোট বা
স্ট্রোকগুলি

এই তিনটি লাইন আপনাকে টাইপ-সুরক্ষা দেয় এবং গ্যারান্টি দেয় যে আপনার নির্বাচক প্রত্যাশার চেয়ে আর্গুমেন্টের সংখ্যা। objc_msgSend হ'ল একটি ভার্জ ফাংশন যা আসলে এসেম্বলি আঠা হিসাবে বাস্তবায়িত হয় তাই যদি আপনি টাইপকাস্ট না করেন তবে আপনি এটি কিছু দিতে পারেন।
জেসন হ্যারিস

1

আপনি কেবল নির্বাচককে কল করতে NSTimer ব্যবহার করতে পারেন:

[NSTimer timerWithTimeInterval:1.0 target:self selector:@selector(yourMethod:) userInfo:nil repeats:NO]

আপনি যুক্তিটি মিস করছেন। yourMethod:আপনার উদাহরণে যুক্তিটি হ'ল টাইমার নিজেই এবং আপনি এর জন্য কিছু পাস করেননি userInfo। এমনকি যদি আপনি এটি ব্যবহার করেন তবে আপনাকে userInfoক্ষতি করতে হবে এবং রেমাস রুসানুর পরামর্শ অনুসারে মানটি বাক্স আপ করতে হবে।
পিটার হোসি

-1 সম্পাদনকারী নির্বাচন না করার জন্য এবং অপ্রয়োজনীয় এনএসটিমারের উদাহরণ তৈরি না করার জন্য
অ্যাপ্লিকেশন আইওএস বিকাশকারী

1

এনএসএনম্বার বা অন্যান্য এনএসভ্যালু দিয়ে পারফর্মসিলিটরকে কল করা কার্যকর হবে না। NSValue / NSNumber এর মান ব্যবহার করার পরিবর্তে এটি কার্যকরভাবে পয়েন্টারটিকে কোনও int, ভাসমান বা যে কোনও কিছুতে এবং এটি ব্যবহার করে cast

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

[invocation performSelector:@selector(invoke) withObject:nil afterDelay:delay]


0

পেপাসস ... ঠিক আছে, খুব সম্ভবত, আমি কিছু মিস করছি তবে সিজিফ্লোয়েটের মতো আপনার অ-অবজেক্ট টাইপের ভেরিয়েবলের ধারক হিসাবে এনএসএনম্বারকে কেন কেবল একটি অবজেক্ট টাইপ তৈরি করবেন না?

CGFloat myFloat = 2.0; 
NSNumber *myNumber = [NSNumber numberWithFloat:myFloat];

[self performSelector:@selector(MyCalculatorMethod:) withObject:myNumber afterDelay:5.0];

প্রশ্নটি এনএসএনম্বার অবজেক্ট নয়, আদিম প্রকারগুলি পাস করার বিষয়ে।
রুডল্ফ আদমকোভিč

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