2010-04-16 12 views
27

J'essaie de transmettre des données via userInfo pour un appel NSTimer. Quelle est la meilleure façon de procéder? J'essaie d'utiliser un NSDictionary, c'est assez simple quand j'ai des objets Objective-C, mais qu'en est-il d'autres données? Je veux faire quelque chose comme ça, qui ne fonctionne pas tel quel:Passage de données via NSTimer UserInfo

- (void)play:(SystemSoundID)sound target:(id)target callbackSelector:(SEL)selector 
{ 
    NSLog(@"pause ipod"); 
    [iPodController pause]; 
    theSound = sound; 

    NSMutableDictionary *cb = [[NSMutableDictionary alloc] init]; 
    [cb setObject:(id)&sound forKey:@"sound"]; 
    [cb setObject:target forKey:@"target"]; 
    [cb setObject:(id)&selector forKey:@"selector"]; 

    [NSTimer scheduledTimerWithTimeInterval:0 
            target:self 
            selector:@selector(notifyPause1:) 
            userInfo:(id)cb 
            repeats:NO]; 
} 
+0

Est-ce que 'cb' est nul quand vous obtenez' -notifyPause1: '? –

Répondre

7

Votre appel est juste, mais vous ne devez pas jeter le dictionnaire id. Vous pouvez obtenir le userInfo retour avec la ligne suivante dans votre notifyPause1: Méthode:

- (void)notifyPause1:(NSTimer *)timer { 

    NSDictionary *dict = [timer userInfo]; 

} 
2

sound et selector ne sont pas des objets Objective-C: sound est un nombre non signé et selector est un pointeur vers une struct C. C'est susceptible de provoquer un accident quelconque. Vous devez utiliser NSValue pour conserver la valeur selector et NSNumber pour la valeur sound. NSValue et NSNumber sont des objets et fonctionneront avec NSMutableDictionary.

0

Vous ne devez pas diffuser vos objets dans un ID lors de l'affectation au dictionnaire. Tout objet qui peut être directement incorporé dans un NSDictionary dérive déjà de NSObject et est implicitement converti en id. Conservez le nom du sélecteur comme NSString (en utilisant NSStringFromSelector()) puis reconvertir à un sélecteur à l'aide NSSelectorFromString()

Claus

49

Vous devez envelopper les informations correctement dans le dictionnaire:

- (void) play:(SystemSoundID)sound target:(id)target callbackSelector:(SEL)selector 
{ 
    NSLog(@"pause ipod"); 
    [iPodController pause]; 
    theSound = sound; 

    NSMutableDictionary *cb = [[NSMutableDictionary alloc] init]; 
    [cb setObject:[NSNumber numberWithInt:sound] forKey:@"sound"]; 
    [cb setObject:target forKey:@"target"]; 
    [cb setObject:NSStringFromSelector(selector) forKey:@"selector"]; 

    [NSTimer scheduledTimerWithTimeInterval:0 
            target:self 
            selector:@selector(notifyPause1:) 
            userInfo:cb 
            repeats:NO]; 
    [cb release]; 

} 

Dans notifyPause1:, vous récupérez tout:

- (void)notifyPause1:(NSTimer *)timer { 
    NSDictionary *dict = [timer userInfo]; 

    SystemSoundID sound = [[dict objectForKey:@"sound"] intValue]; 
    id target = [dict objectForKey:@"target"]; 
    SEL selector = NSSelectorFromString([dict objectForKey:@"selector"]); 

    // Do whatever... 
} 

Comme la minuterie est une minuterie répétitive, vous n'avez plus besoin du dictionnaire, vous pouvez donc le libérer.

+0

Un heads up - si vous appelez * invalidate * pour votre NSTimer, assurez-vous de vérifier le drapeau * isValid * avant d'accéder à * userInfo *. Ceci est indiqué dans la documentation de la propriété * userInfo *, et je viens d'attraper un crash à cet endroit précis. – NAlexN

6

Vous pouvez demander la minuterie dans la méthode donnée au sélecteur,

Ensuite, vous pouvez saisir useInfo de cette minuterie (timer.userInfo):

- (void)settingTimer 
{ 
[NSTimer scheduledTimerWithTimeInterval:kYourTimeInterval 
           target:self 
           selector:@selector(timerFired:) 
           userInfo:yourObject 
           repeats:NO]; 
} 

- (void)timerFired:(NSTimer*)theTimer 
{ 
    id yourObject = theTimer.userInfo; 
    //your code here 
} 
méthode de
2

Laurent Etiemble fonctionne bien pour faire bon usage des méthodes de minuterie dans les sous-classes de UIViewcontroller qui peuvent être facilement utilisées dans un certain nombre de contrôleurs de vue différents. Voici un moyen d'écrire un affichage de score générique qui peut être utilisé encore et encore dans la même application en passant la vue via NSTimer userInfo.

.h (sous-classe de UIViewController)

- (NSTimeInterval) timeSet; 
    - (void) timeRun: (UISegmentedControl*)scoreDisplay; 
    - (void) timeWrite: (NSTimer *)timer; 

.m

  - (NSTimeInterval) timeSet { 
       return [self.startTime timeIntervalSinceNow]; 
      } 

      - (void) timeWrite: (NSTimer *)timer 
      { 
       NSDictionary *dict = [timer userInfo]; 
       UISegmentedControl *scoreDisplay = [dict objectForKey:@"scoreDisplay"]; 

       int myint = round([self timeSet]); 
       NSString* buttonWrite = [[[NSString stringWithFormat:@"Score: %d", self.answered] stringByAppendingString:[NSString stringWithFormat:@" Errors: %d", self.errors]] stringByAppendingString:[NSString stringWithFormat:@" Time: %d", (myint*-1)]]; 

       [scoreDisplay setTitle:buttonWrite forSegmentAtIndex:0]; 
      } 

      - (void) timeRun: (UISegmentedControl*)scoreDisplay 
      { 
       self.startTime = [NSDate date]; 

       NSMutableDictionary *cb = [[NSMutableDictionary alloc] init]; 
       [cb setObject:scoreDisplay forKey:@"scoreDisplay"]; 

       self.myTimer = [NSTimer scheduledTimerWithTimeInterval:1 
                   target:self 
                   selector:@selector(timeWrite:) 
                   userInfo:cb 
                   repeats:YES]; 

      } 

Dans le contrôleur de vue

.m

- (void)viewDidLoad 
    { 
     [super viewDidLoad]; 

     //load ScoreDisplay 
     [self timeRun:self.scoreDisplay]; 

    }