1
votes

I tried to implement alarm and person relations in the morning through delegate and to simulate delays after each ring used performSelector:@selector withObject:nil afterDelay. But no function calls performed, but when I use simply performSelector: - it works fine. All in main thread. Can somebody explain that? Here is my code:

    #import <Foundation/Foundation.h>

    @protocol MyDelegateProtocol <NSObject>

    @optional
    - (void) wakeUp;
    - (void) standUp;

    @end

#import <Foundation/Foundation.h>
#import "myDelegateProtocol.h"

@interface Alarm : NSObject

@property (nonatomic, weak) id <MyDelegateProtocol> delegate;
@property (nonatomic, assign) NSUInteger ringsLeft;
@property (nonatomic, assign) SEL selector;

- (void) setAlarm: (CGFloat) delay;
- (void) fiveMinutesMore;
- (id) initWithRings: (NSUInteger) rings;
- (void) doAlarm;


@end

#import "Alarm.h"

@implementation Alarm

@synthesize delegate;
@synthesize selector;

- (id) initWithRings:(NSUInteger)rings
{
    self = [super init];
    if (self) {
        self.ringsLeft = rings;
    }
    return self;
}
- (void)setAlarm:(CGFloat)delay {
    if (delegate) {
        if (self.ringsLeft>0) {
            self.ringsLeft--;
            selector = @selector(wakeUp);
        } else {
            selector = @selector(standUp);
        }
    }
    if ([delegate respondsToSelector:selector]) {
        [self performSelector:@selector(doAlarm)];
//        [self performSelector:@selector(doAlarm) withObject:nil afterDelay:delay];
    }
}
- (void)doAlarm {
    [delegate performSelector:selector];
}
- (void)fiveMinutesMore {
    [self setAlarm:1.0];
}

@end

#import <Foundation/Foundation.h>
#import "Alarm.h"

@interface Person : NSObject <MyDelegateProtocol>

@property (nonatomic,assign) NSUInteger chanceToWakeUp;
@property (nonatomic,strong) Alarm *myAlarm;

- (void) goSleepFor: (CGFloat) seconds;
- (id) init;

@end

#import "Person.h"

@implementation Person

@synthesize chanceToWakeUp;
@synthesize myAlarm;

-(void) goSleepFor:(CGFloat)seconds
{
    NSLog(@"Going for a sleep");
    [myAlarm setAlarm:seconds];
}
-(void) wakeUp
{
    NSLog(@"Ringing...");
    NSUInteger randomNumber = arc4random_uniform(6);
    if (randomNumber>chanceToWakeUp) {
        chanceToWakeUp++;
        NSLog(@"Person takes five minutes more to sleep");
        [myAlarm fiveMinutesMore];
    } else {
        [self standUp];
    }
}
-(void) standUp
{
    NSLog(@"Person stand's up");
}
-(id) init
{
    self = [super init];
    if (self) {
        chanceToWakeUp=0;
        myAlarm = [[Alarm alloc] initWithRings:5];
        myAlarm.delegate=self;
    }
    return self;
}

@end

#import <Foundation/Foundation.h>
#import "Person.h"


int main(int argc, const char * argv[]) {
    @autoreleasepool {
        Person *tiredPerson = [[Person alloc] init];
        [tiredPerson goSleepFor:10.0f];
    }
    return 0;
}
4
Creating a ivar with the name selector if a very poor idea, it just tends to cause confusion. Method names shouls say what they do. It is also not necessary to `@synthesize1, that happens automatically and creates an ivar with "_" prepended to the name, use self.ivar to access. - zaph
Only sleep(delay) works with #import "unistd.h". Neither of [self performSelector:@selector(doAlarm) withObject:nil afterDelay:delay]; and [NSTimer timerWithTimeInterval:delay target:self selector:@selector(doAlarm) userInfo:nil repeats:NO]; works at all - Dmytro Kolochynskyj

4 Answers

0
votes

I think your program is terminating before your delay time out. Try adding:

[[NSRunLoop currentRunLoop] run]

after your goToSleepFor: call.

0
votes

To use:

[self performSelector:@selector(doAlarm:) withObject:nil afterDelay:delay];

the method must be defined to take an argument:

- (void)doAlarm:(id)object {

or

[self performSelector:@selector(doAlarm) withObject:nil afterDelay:delay];

the method must be defined to take an argument:

- (void)doAlarm {
0
votes

Performing a selector with delay queues the operation on the current run loop. You didn't start any run loops in your program. Your program simply calls some functions synchronously which return and then your program exits.

0
votes

if your code is running when the run loop is in a mode other than the default mode, try this:

        [self performSelector:@selector(doAlarm) withObject:nil
               afterDelay:delay
                  inModes:@[[[NSRunLoop currentRunLoop] currentMode]]];