问题
I am trying to pass data through userInfo for an NSTimer call. What is the best way to do this? I am trying to use an NSDictionary, this is simple enough when I have Objective-C objects, but what about other data? I want to do something like this, which doesn't work as is:
- (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];
}
回答1:
You have to wrap the information correctly into the dictionary:
- (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];
}
In notifyPause1:
, you retrieve everything:
- (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...
}
As the timer is a repeating timer, you do not need the dictionary anymore, so you can release it.
回答2:
Your call is right, but you don't have to cast the dictionary to id. You can get the userInfo back with the following line in your notifyPause1: method:
- (void)notifyPause1:(NSTimer *)timer {
NSDictionary *dict = [timer userInfo];
}
回答3:
You may ask for the timer in the method given to the selector,
Then you can grab useInfo from that timer (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
}
回答4:
sound
and selector
aren't Objective-C objects: sound
is an unsigned number and selector
is a pointer to a C struct . That's likely to cause a crash of some sort.
You'll want to use NSValue to hold the value for selector
and NSNumber to hold the value for sound
. NSValue and NSNumber are objects and will work with the NSMutableDictionary.
回答5:
Laurent Etiemble's method works well for making good use of timer methods in subclasses of UIViewcontroller which can be easily used in a number of different view controllers.
Below is a way to write a generic score display which can be used over and over in the same app by passing the view through NSTimer userInfo.
.h (subclass of 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];
}
In the view controller
.m
- (void)viewDidLoad
{
[super viewDidLoad];
//load ScoreDisplay
[self timeRun:self.scoreDisplay];
}
回答6:
You should not cast your objects to id when assigning to the dictionary. Any object that can be embedded directly into a NSDictionary
already derives from NSObject
and are implicitly concidered cast to id.
Store the name of the selector as an NSString
(using NSStringFromSelector()
) and then convert it back to a selector using NSSelectorFromString()
Claus
来源:https://stackoverflow.com/questions/2651882/passing-data-through-nstimer-userinfo