Tests get blocked when testing asynchronous network stuff with Nocilla - objective-c

I'm trying to test a class that has a method responding asynchronously that makes a network call, stubbed by Nocilla.
The tests runs fine when I run the test alone. But as soon as I launch my whole test suite, it blocks here for a while and finishes with a:
Thread 1: signal SIGABRT
Here is my test class:
#interface SMIMyServiceTests : XCTestCase
#property (strong, nonatomic) SMIMyService *service;
#end
#implementation SMIMyServiceTests
+ (void)setUp {
[[LSNocilla sharedInstance] start];
}
+ (void)tearDown {
[[LSNocilla sharedInstance] stop];
}
- (void)setUp {
[super setUp];
self.service = [[SMIMyService alloc] init];
}
- (void)tearDown {
[[LSNocilla sharedInstance] clearStubs];
self.service = nil;
[super tearDown];
}
- (void)testFetch {
stubRequest(#"GET", #"http://mydevserver.192.168.1.15.xip.io/api/data.json").andReturn(200).withBody([MyUtil jsonFromFile:#"json-file" sender:self]);
XCTestExpectation *expectation = [self expectationWithDescription:#"Fetch"];
[self.service fetch:^(NSArray *data) {
XCTAssertTrue(data != nil);
XCTAssertEqual(data.count, 7);
[expectation fulfill];
}];
[self waitForExpectationsWithTimeout:5.0 handler:nil];
}
#end
Any idea what's going wrong?

Related

Objective C protocol method is not called

I have created singleton class for AVAudioPlayer. I am able to call the methods in the class and everything works fine. When the song finishes,the method (void)audioPlayerDidFinishPlaying is called which in turn suppose to call the method ' processSuccessful' in my downloadPlay.m class. But, it is not calling the method 'processSuccessful'
My codes as follows
PlayerManager.h
#import <Foundation/Foundation.h>
#import <AudioToolbox/AudioToolbox.h>
#import <AVFoundation/AVFoundation.h>
#protocol ProcessDataDelegate <NSObject>
#required
- (void) processSuccessful;
#end
#interface PlayerManager : NSObject<AVAudioPlayerDelegate,AVAudioSessionDelegate>
{
id <ProcessDataDelegate> delegate;
}
+ (PlayerManager *)sharedAudioPlayer;
#property (nonatomic,assign) id <ProcessDataDelegate>delegate;
#property (nonatomic, strong) AVAudioPlayer* player;
-(void)preparesong:(NSURL *)url;
-(void)stopsong;
-(void)pause;
-(void)playsong;
-(void)prepareToPlay;
-(BOOL)isPlaying;
-(BOOL)isPlayerExist;
#end
PlayerManager.m
#import "PlayerManager.h"
#interface PlayerManager()
#end
#implementation PlayerManager
#synthesize player;
#synthesize delegate;
static PlayerManager *sharedAudioPlayer = nil;
+ (PlayerManager *)sharedAudioPlayer {
static PlayerManager *sharedAudioPlayer = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
sharedAudioPlayer = [[self alloc] init];
});
return sharedAudioPlayer ;
}
- (void)audioPlayerEndInterruption:(AVAudioPlayer *)player withOptions:(NSUInteger)flags
{
if (flags & AVAudioSessionInterruptionOptionShouldResume)
{
[self.player play];
}
}
- (void)audioPlayerBeginInterruption:(AVAudioPlayer *)player
{
}
#pragma mark - AVAudioPlayerDelegate
- (void)audioPlayerDidFinishPlaying:(AVAudioPlayer *)player successfully:(BOOL)flag
{
[[self delegate] processSuccessful];
}
- (void)audioPlayerDecodeErrorDidOccur:(AVAudioPlayer *)player error:(NSError *)error
{
}
-(void)preparesong:(NSURL *)url
{
[[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryPlayback error:nil];
NSError *error;
self.player = [[AVAudioPlayer alloc] initWithContentsOfURL:url error:&error];
if(!self.player)
{
NSLog(#"Error creating player: %#", error);
}
self.player.delegate = self;
[self.player prepareToPlay];
}
-(BOOL)isPlayerExist
{
if (player)
return YES;
return NO;
}
-(BOOL)isPlaying
{
if (player && player.playing)
return YES;
return NO;
}
-(void)prepareToPlay
{
if (player)
[self.player prepareToPlay];
}
-(void)playsong
{
if (player)
[self.player play];
}
-(void)pause
{
if (player.playing)
[self.player pause];
}
-(void)stopsong
{
if (player)
[self.player stop];
}
#end
downloadPlay.h
#import <UIKit/UIKit.h>
#import <AudioToolbox/AudioToolbox.h>
#import <AVFoundation/AVFoundation.h>
#import "PlayerManager.h"
#interface downloadPlay: UIViewController <UITableViewDelegate,AVAudioPlayerDelegate,ProcessDataDelegate>
{
PlayerManager *protocolPlay;
}
#property (retain, nonatomic) IBOutlet UITableView *tblFiles;
......
- (void)startPlay:(id)sender;
........
#end
downloadPlay.m
import "downloadPlay.h"
#import "PlayerManager.h"
#interface downloadPlay ()
#end
#implementation downloadPlay
.....
- (void)processSuccessful
{
NSLog(#"This method suppose to be called from the method audioPlayerDidFinishPlaying - from PlayerManager");
}
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
protocolPlay = [[PlayerManager alloc]init];
[protocolPlay setDelegate:self];
}
- (void)startPlay
{
............
.........
NSURL *destinationURL = [self.docDirectoryURL URLByAppendingPathComponent:filename];
NSError* error = nil;
[[PlayerManager sharedAudioPlayer]stopsong];
[[PlayerManager sharedAudioPlayer ] preparesong:destinationURL ];
[[PlayerManager sharedAudioPlayer]playsong];
}
#end
In viewDidLoad method you are creating a different object by using
protocolPlay = [[PlayerManager alloc]init];
line and set the delegate of this object while you have to set the delegate of shared object.
Solution is:
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
[[PlayerManager sharedAudioPlayer] setDelegate:self];
}

xmppstream delegate methods not getting called on my custom class

I started with xmppframework recently,but i am stuck with an issue.i am able to connect to my server on my local network but the xmppstreamdelegate methods are not getting called on my custom class,but works absolutely fine on appdelegate class .Can anyone pls help me on this.Is the delegate only supported on the appdelegate class ?
Header:
#interface XmppClass : NSObject<XMPPStreamDelegate>{
XMPPStream *xmppStream;
Login * loginDetail;
BOOL allowSelfSignedCertificates;
BOOL allowSSLHostNameMismatch;
}
#property (nonatomic, strong, readonly) XMPPStream *xmppStream;
#property (nonatomic, strong) Login *loginDetail;
- (id)initWithLogin:(Login *) loginrefernce;
- (BOOL)connect;
- (void)disconnect;
- (void)setupStream;
#end
Implementation:
#implementation XmppClass
#synthesize xmppStream;
#synthesize loginDetail;
- (id)initWithLogin:(Login *) loginrefernce
{
self = [super init];
if (self) {
self.loginDetail=loginrefernce;
[DDLog addLogger:[DDTTYLogger sharedInstance]];
[self setupStream];
[self connect];
}
return self;
}
- (void)setupStream
{
NSAssert(xmppStream == nil, #"Method setupStream invoked multiple times");
// Setup xmpp stream
//
// The XMPPStream is the base class for all activity.
// Everything else plugs into the xmppStream, such as modules/extensions and delegates.
xmppStream = [[XMPPStream alloc] init];
#if !TARGET_IPHONE_SIMULATOR
{
// Want xmpp to run in the background?
//
// P.S. - The simulator doesn't support backgrounding yet.
// When you try to set the associated property on the simulator, it simply fails.
// And when you background an app on the simulator,
// it just queues network traffic til the app is foregrounded again.
// We are patiently waiting for a fix from Apple.
// If you do enableBackgroundingOnSocket on the simulator,
// you will simply see an error message from the xmpp stack when it fails to set the property.
xmppStream.enableBackgroundingOnSocket = YES;
}
#endif
NSLog(#"setup stream");
[xmppStream addDelegate:self delegateQueue:dispatch_get_main_queue()];
[xmppStream setHostName:#"10.68.202.123"];
//[xmppStream setHostPort:8070];
allowSelfSignedCertificates = NO;
allowSSLHostNameMismatch = NO;
// You may need to alter these settings depending on the server you're connecting to
}
- (BOOL)connect
{
NSLog(#"connect");
if (![xmppStream isDisconnected]) {
return YES;
}
//
// If you don't want to use the Settings view to set the JID,
// uncomment the section below to hard code a JID and password.
//
// myJID = #"user#gmail.com/xmppframework";
// myPassword = #"";
if (self.loginDetail.emailId == nil || self.loginDetail.password == nil) {
return NO;
}
[xmppStream setMyJID:[XMPPJID jidWithString:[self.loginDetail.emailId stringByAppendingString:#"/pc"]]];
NSError *error = nil;
if (![xmppStream connect:&error])
{
NSLog(#"Error connecting: %#", error);
return NO;
}
return YES;
}
- (void)disconnect
{
[xmppStream disconnect];
}
- (void)xmppStream:(XMPPStream *)sender socketDidConnect:(GCDAsyncSocket *)socket
{
DDLogVerbose(#"%#: %#", THIS_FILE, THIS_METHOD);
}
- (void)xmppStream:(XMPPStream *)sender willSecureWithSettings:(NSMutableDictionary *)settings
{
DDLogVerbose(#"%#: %#", THIS_FILE, THIS_METHOD);
NSLog(#"some security thing");
if (allowSelfSignedCertificates)
{
[settings setObject:[NSNumber numberWithBool:YES] forKey:(NSString *)kCFStreamSSLAllowsAnyRoot];
}
if (allowSSLHostNameMismatch)
{
[settings setObject:[NSNull null] forKey:(NSString *)kCFStreamSSLPeerName];
}
else
{
// Google does things incorrectly (does not conform to RFC).
// Because so many people ask questions about this (assume xmpp framework is broken),
// I've explicitly added code that shows how other xmpp clients "do the right thing"
// when connecting to a google server (gmail, or google apps for domains).
NSString *expectedCertName = nil;
NSString *serverDomain = xmppStream.hostName;
NSString *virtualDomain = [xmppStream.myJID domain];
if ([serverDomain isEqualToString:#"talk.google.com"])
{
if ([virtualDomain isEqualToString:#"gmail.com"])
{
expectedCertName = virtualDomain;
}
else
{
expectedCertName = serverDomain;
}
}
else if (serverDomain == nil)
{
expectedCertName = virtualDomain;
}
else
{
expectedCertName = serverDomain;
}
if (expectedCertName)
{
[settings setObject:expectedCertName forKey:(NSString *)kCFStreamSSLPeerName];
}
}
}
- (void)xmppStreamDidSecure:(XMPPStream *)sender
{
DDLogVerbose(#"%#: %#", THIS_FILE, THIS_METHOD);
}
- (void)xmppStreamDidConnect:(XMPPStream *)sender
{
DDLogVerbose(#"%#: %#", THIS_FILE, THIS_METHOD);
NSLog(#"connected");
NSError *error = nil;
if (![[self xmppStream] authenticateWithPassword:self.loginDetail.password error:&error])
{
DDLogError(#"Error authenticating: %#", error);
}
}
- (void)xmppStreamDidAuthenticate:(XMPPStream *)sender
{
DDLogVerbose(#"%#: %#", THIS_FILE, THIS_METHOD);
NSLog(#"authenticated");
}
- (void)xmppStream:(XMPPStream *)sender didNotAuthenticate:(NSXMLElement *)error
{
DDLogVerbose(#"%#: %#", THIS_FILE, THIS_METHOD);
NSLog(#"did not authenticate");
}
- (BOOL)xmppStream:(XMPPStream *)sender didReceiveIQ:(XMPPIQ *)iq
{
DDLogVerbose(#"%#: %#", THIS_FILE, THIS_METHOD);
return NO;
}
- (void)xmppStream:(XMPPStream *)sender didReceiveMessage:(XMPPMessage *)message
{
DDLogVerbose(#"%#: %#", THIS_FILE, THIS_METHOD);
// A simple example of inbound message handling.
}
- (void)xmppStream:(XMPPStream *)sender didReceivePresence:(XMPPPresence *)presence
{
DDLogVerbose(#"%#: %# - %#", THIS_FILE, THIS_METHOD, [presence fromStr]);
}
- (void)xmppStream:(XMPPStream *)sender didReceiveError:(id)error
{
DDLogVerbose(#"%#: %#", THIS_FILE, THIS_METHOD);
}
- (void)xmppStreamDidDisconnect:(XMPPStream *)sender withError:(NSError *)error
{
DDLogVerbose(#"%#: %#", THIS_FILE, THIS_METHOD);
NSLog(#"%#",error);
}
#end
Most probably the problem is that your class instance, that is a delegate for your XMPPStream is released before the delegate method is called on it. Make it more persistent by making this class a property or instance variable of other class or by using dispatch_once. For example,
Change
YourClass *instance = [[YourClass alloc] init];
instance.xmppStream = ....
by
#property(nonatomic, strong) YourClass *instance;
self.instance = [[YourClass alloc] init];
self.instance.xmppStream = ....
Here YourClass contains XMPPStream and is delegate for it.
I've written a big blog post on this problem. This is pretty common situation.
http://blog.alwawee.com/2013/07/31/on-xmppframework-delegate-method-not-being-called/
you can use the multicast,sth like this
[[self appDelegate].xmppStream addDelegate:self delegateQueue:dispatch_get_main_queue()];
I had same problem... this helped me. Hope it works for you, just make following Changes in your code.
Static XmppClass *selfRef = nil;
#implementation XmppClass
#synthesize xmppStream;
- (void)setupStream
{
// Setup xmpp stream
selfRef = [[XmppClass alloc] init];
xmppStream = [[XMPPStream alloc] init];
[xmppStream addDelegate:selfRef delegateQueue:dispatch_get_main_queue()];

Why is my NSOperation subclass never finishing?

I have an NSOperation subclass that I want to run concurrently.
My understanding is that for concurrent operations to work:
I need to define isConcurrent to return YES.
I need to define the start method
I need to send KVOs notification for isExecuting and isFinished when it's done.
Using #synthesize will automatically send the appropriate KVO notifications when the values for isExecuting and isFinished are changed.
Despite this, I have verified that my queue never moves on to the next item.
Here's the meat of my code:
#interface MyOperation()
#property (readwrite) BOOL isExecuting;
#property (readwrite) BOOL isFinished;
#end
#implementation MyOperation
- (void)start
{
#autoreleasepool {
self.isExecuting = YES;
self.HTTPOperation = [[AFHTTPRequestOperation alloc] initWithRequest: URLRequest];
_HTTPOperation.completionBlock = [^{
[self completed];
self.isExecuting = NO;
self.isFinished = YES;
} copy];
[_HTTPOperation start];
}
}
- (BOOL)isConcurrent
{
return YES;
}
- (void)completed
{
}
#end
What am I missing?
(This is on an iPhone, but I can't imagine that matters.)
It looks like whatever KVO notifications #synthesize sends aren't enough for NSOperationQueue to move on.
Sending the notifications manually fixes the problem:
- (void)start
{
#autoreleasepool {
[self willChangeValueForKey:#"isExecuting"];
self.isExecuting = YES;
[self didChangeValueForKey:#"isExecuting"];
NSURLRequest *URLRequest = [self buildRequest];
if (!URLRequest) {
[self willChangeValueForKey:#"isFinished"];
[self willChangeValueForKey:#"isExecuting"];
_isExecuting = NO;
_isFinished = YES;
[self didChangeValueForKey:#"isExecuting"];
[self didChangeValueForKey:#"isFinished"];
return;
}
self.HTTPOperation = [[AFHTTPRequestOperation alloc] initWithRequest: URLRequest];
_HTTPOperation.completionBlock = [^{
[self completed];
[self willChangeValueForKey:#"isFinished"];
[self willChangeValueForKey:#"isExecuting"];
_isExecuting = NO;
_isFinished = YES;
[self didChangeValueForKey:#"isExecuting"];
[self didChangeValueForKey:#"isFinished"];
} copy];
[_HTTPOperation start];
}
}
See also:
Why does NSOperation disable automatic key-value observing?
What's your "queue" look like? Are you using an NSOperationQueue?
Anyway, I'll try to answer your question with what I understood :P
I would create a delegate for my NSOperation and have KVO take care of calling this.
Say for example your NSOperation class looks like this
#interface MyOperation : NSOperation
#property (assign) id<MyOperationDelegate> delegate;
Your implementation
#synthesize delegate;
#synthesize error;
-(id)init{
self = [super init];
if(self){
[self addObserver:self forKeyPath:#"isFinished"
options:NSKeyValueObservingOptionNew
context:NULL];
}
return self;
}
-(void)dealloc{
[self removeObserver:self forKeyPath:#"isFinished"];
[super dealloc];
}
-(void)observeValueForKeyPath:(NSString *)keyPath
ofObject:(id)object change:(NSDictionary *)change context:(void *)context{
if([keyPath isEqualToString:#"isFinished"] == YES){
if([self isCancelled] == NO){
if(delegate != nil && [delegate respondsToSelector:#selector(operationComplete:)]){
[delegate taskComplete:self];
}
}else{
if(delegate != nil && [delegate respondsToSelector:#selector(operationCancelled)]){
[delegate taskCancelled];
}
}
}
}
-(void)main{
[NSException exceptionWithName:kTaskException
reason:#"Only to be used with subclass"
userInfo:nil];
}
And finally your protocol
#class MyOperation;
#protocol MyOperationDelegate <NSObject>
#optional
-(void)operationComplete:(MyOperation*)operation;
-(void)operationCancelled;

Why is Xcode saying my class implementation is incomplete?

I have created a singleton for my MusicBackground. And I receive a line code of imcomplete implementation of this line #implementation MyBgMusic. Can anyone tell me why ? Below is the code:
#import "MyBgMusic.h"
static MyBgMusic *sharedMyManager = nil;
#implementation MyBgMusic
#synthesize player,playBgMusic;
#pragma mark -
#pragma mark Singleton Methods
+ (MyBgMusic*)sharedInstance {
static MyBgMusic *_sharedInstance;
if(!_sharedInstance) {
static dispatch_once_t oncePredicate;
dispatch_once(&oncePredicate, ^{
_sharedInstance = [[super allocWithZone:nil] init];
});
}
return _sharedInstance;
}
+ (id)allocWithZone:(NSZone *)zone {
return [self sharedInstance];
}
- (id)copyWithZone:(NSZone *)zone {
return self;
}
#if (!__has_feature(objc_arc))
- (id)retain {
return self;
}
- (unsigned)retainCount {
return UINT_MAX; //denotes an object that cannot be released
}
- (id)autorelease {
return self;
}
- (void)dealloc
{
[MyBgMusic release];
[playBgMusic release];
[player release];
[super dealloc];
}
#endif
#pragma mark -
#pragma mark Custom Methods
- (void)viewDidLoad
{
NSString *path = [[NSBundle mainBundle] pathForResource:#"music" ofType:#"mp3"];
self.player=[[AVAudioPlayer alloc] initWithContentsOfURL:[NSURL fileURLWithPath:path] error:NULL];
player.delegate = self;
[player play];
player.numberOfLoops = -1;
[super viewDidLoad];
}
#end
For the M file, below is the code:
#import <Foundation/Foundation.h>
#import <AVFoundation/AVAudioPlayer.h>
#interface MyBgMusic : UIViewController <AVAudioPlayerDelegate> {
AVAudioPlayer *player;
UIButton *playBgMusic;
}
#property (nonatomic, retain) IBOutlet AVAudioPlayer *player;
#property (nonatomic, retain) IBOutlet UIButton *playBgMusic;
+ (id)sharedManager;
-(IBAction) toggleMusic;
#end
And how do I reference to my toggle button: Below is the code :
- (IBAction)toggleMusic {
if ([self.player isPlaying] == YES) {
[self.player stop];
} else {
[self.player play];
}
self.playBgMusic.enabled = YES;
}
It means that your MyBgMusic class isn't doing everything it promised to do in its header file, which includes being a UIViewController and implementing the AVAudioPlayerDelegate protocol. I'm not familiar with exactly what the AVAudioPlayerDelegate is, but it's quite possible that your class doesn't implement all of the required methods.
Also, you're declaring methods +(id)sharedManager and -(IBAction)toggleMusic, but I don't see them anywhere in the implementation file. That would be a case of promising something in the header and not implementing it in the class.
It would help if you posted the actual error message.
That error means your #implementation section does not contain everything described in the #interface section.
I can see two problems.
First you need to place this code:
- (IBAction)toggleMusic {
...
}
Somewhere in between #implementation and #end.
And you also need to rename the line + (MyBgMusic*)sharedInstance to + (id)sharedManager.
EDIT:
To access the toggle music method elsewhere in your code, you would do:
[[MyBgMusic sharedManager] toggleMusic];
Your +(id)sharedManagerimplementation is called +(id)sharedInstance. Just guessing, but it seems they are supposed to do the same.

NSCondition ->Objective C

I am a newbie to Objective-C. I'm currently working on threads.
I have to make a synchronous execution of threads. I'm using NSInvocationOperaion to spawn a thread.
I have two threads. I need to wait for the 1st thread to signal a event or the timeout.
Signalling a event can be done by NSConditionLock. How to signal a timeout. I could not use waitUntilDate method here as the timeout is not a fixed value.
Is there any way to do this?
EDITED
main.m
------
#import "PseudoSerialQueue.h"
#import "PseudoTask.h"
int main()
{
PseudoSerialQueue* q = [[[PseudoSerialQueue alloc] init] autorelease];
[q addTask:self selector:#selector(test0)];
[q addTask:self selector:#selector(test1)];
[q addTask:self selector:#selector(test2)];
[q quit];
return 0;
}
PseudoTask.h
-----------------
#import <Foundation/Foundation.h>
#interface PseudoTask : NSObject {
id target_;
SEL selector_;
id queue_;
}
#property(nonatomic,readonly)id target;
-(id)initWithTarget:(id)target selector:(SEL)selector queue:(id)queue;
-(void)exec;
#end
PseudoTask.m
-----------------
#import "PseudoTask.h"
#implementation PseudoTask
#synthesize target = target_;
-(id)initWithTarget:(id)target selector:(SEL)selector queue:(id)queue
{
self = [super init];
if (self) {
target_ = [target retain];
selector_ = selector;
queue_ = [queue retain];
}
return self;
}
-(void)exec
{
[target_ performSelector:selector_];
}
-(void)dealloc
{
[super dealloc];
[target_ release];
[queue_ release];
}
#end
PseudoSerialQueue.h
----------------------------
#import <Foundation/Foundation.h>
#import "PseudoTask.h"
#interface PseudoSerialQueue : NSObject {
NSCondition* condition_;
NSMutableArray* array_;
NSThread* thread_;
}
-(void)addTask:(id)target selector:(SEL)selector;
#end
PseudoSerialQueue.m
----------------------------
#import "PseudoSerialQueue.h"
#implementation PseudoSerialQueue
-(id)init
{
self = [super init];
if (self) {
array_ = [[NSMutableArray alloc]init];
condition_ = [[NSCondition alloc]init];
thread_ = [[NSThread alloc] initWithTarget:self selector:#selector(execQueue) object:nil];
[thread_ start];
}
return self;
}
-(void)addTask:(id)target selector:(SEL)selector
{
[condition_ lock];
PseudoTask* task = [[PseudoTask alloc] initWithTarget:target selector:selector queue:self];
[array_ addObject:task];
[condition_ signal];
[condition_ unlock];
}
-(void)quit
{
[self addTask:nil selector:nil];
}
-(void)execQueue
{
for(;;)
{
NSAutoreleasePool* pool = [[NSAutoreleasePool alloc]init];
[condition_ lock];
if (array_.count == 0) {
[condition_ wait];
}
PseudoTask* task = [array_ objectAtIndex:0];
[array_ removeObjectAtIndex:0];
[condition_ unlock];
if (!task.target) {
[pool drain];
break;
}
[task exec];
[task release];
[pool drain];
}
}
-(void)dealloc
{
[array_ release];
[condition_ release];
[super dealloc];
}
#end
I could not pass self from main.Hope i'm mistakenly calling it.
Error:'self' undeclared is coming.
I could not understand
-(void)exec
{
[target_ performSelector:selector_];
}
in PseudoTask.m
target_ is not a method and its an ivar.
I am not getting any error or warning.But i could not understand that code.
I am writing what i have understood from your program.Please correct me if i my way of understanding the program is wrong.
The Thread execQueue is spawned when the PseudoSerialQueue is initialised and it waits for the signal from the addTask method.
The addTask method is called in the quit method and the parameters passed are nil.I could not understand why to pass a nil parameter.
It would be helpful if you explain about it.Thanks.
You mean NSCondition? You can use waitUntilDate: as relative time.
[condition lock];
// wait 5 seconds.
[condition waitUntilDate:[NSDate dateWithTimeIntervalSinceNow:5]];
[condition unlock];
EDITED:
My PseudoSerialQueue class requires to be called from a class that is derived from NSObject like the following.
#interface Test : NSObject
#end
#implementation Test
- (void)test0
{
}
- (void)test1
{
}
- (id)init
{
self = [super init];
return self;
}
- (void)exec
{
PseudoSerialQueue *q = [[PseudoSerialQueue alloc] init];
[q addTask:self selector:#selector(test0)];
[q addTask:self selector:#selector(test1)];
[q addTask:self selector:#selector(test0)];
[q quit];
}
#end
You can call it from main function.
Test *test = [[Test alloc] init];
[test exec];
I could not understand why to pass a nil parameter.
I just only chose it for the message of quitting the loop in the PseudoSerialQueue.
Let the 1st thread signal the 2nd one in both cases; then in the second thread you can tell in which case you are based on some read-only flag in the 1st controller or in your model (say, isDataAvailable).