Error in NSLog:
*** -[NSThread initWithTarget:selector:object:]: target does not implement selector (*** -[Document myTcpClient])
code:
-(void) myTcpStart: (NSButton*) button{
//need threads for the following
thread_Client = [[NSThread alloc] initWithTarget:self selector:#selector(myTcpClient) object:nil];
thread_Display = [[NSThread alloc] initWithTarget:self selector:#selector(displayData) object:nil];
[thread_Client start];
[thread_Display start];
[textField1 setStringValue:#"waiting for threads to run"];
}
-(void) myTcpStop: (NSButton*) button{
//need threads for the following
//[thread_Client cancel];
//[thread_Display cancel];
}
-(void) displayData{
while(1){
[textField1 setStringValue:[NSString stringWithFormat:#"%d %d %f", j, i, genValue]];
j++;
}
}
-(void) myTcpClien{
//some code
}
header file:
#import <Cocoa/Cocoa.h>
#interface Document : NSDocument
{
NSTextField *textField1;
int i;
int j;
double genValue;
NSWindowController *bController;
NSThread *thread_Client;
NSThread *thread_Display;
}
-(void) myTcpClient;
-(void) displayData;
-(void) myTcpStart: (NSButton*) button;
-(void) myTcpStop: (NSButton*) button;
#end
You forgot the T in myTcpClient implementation. Again when you see these messages check your code for spelling errors.
Change:
- (void)myTcpClien { /* ... */ }
To:
- (void)myTcpClient { /* ... */ }
Related
My app crashed, suspected to be caused by multi-threaded operation of an attribute in a singleton object.
So I wrote a small piece of code and successfully reproduced the problem, but I still couldn't understand it.
I have defined the property as #property, which is atomic. Why does it still crash when accessed by multiple threads? Below is my code snippet:
Audio.h
#interface Audio : NSObject
#property NSString *audioName;
#property NSString *audioData;
#end
Audio.m
#import "Audio.h"
#implementation Audio
- (instancetype)init{
self = [super init];
if (self) {
_audioData = #"";
_audioName = nil;
}
return self;
}
#end
AudioManager.h
#interface AudioManager : NSObject
+(instancetype)shareInstance;
#property Audio *curAudio;
-(void) play;
-(void) clearCurAudio;
#end
AudioManager.m
#import "AudioManager.h"
#implementation AudioManager
static id sharedInstance = nil;
+(instancetype)shareInstance {
static dispatch_once_t predicate;
dispatch_once(&predicate, ^{
sharedInstance = [[self alloc] init];
});
return sharedInstance;
}
-(void) play {
NSLog(#"Current Audio name : %#",_curAudio.audioName);
NSLog(#"Current Audio name : %#",_curAudio.audioData);
NSLog(#"Current Audio name : %#",_curAudio.audioName);//crahed here!
NSLog(#"Current Audio name : %#",_curAudio.audioData);
}
-(void) clearCurAudio {
_curAudio = nil;
}
#end
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
dispatch_queue_t thread1 = dispatch_queue_create("queue1", nil);
dispatch_queue_t thread2 = dispatch_queue_create("queue2", nil);
dispatch_queue_t thread3 = dispatch_queue_create("queue3", nil);
dispatch_async(thread1, ^{
for (int i = 0; i < 1000; i++) {
Audio *newAudio = [[Audio alloc] init];
newAudio.audioName = #"na";
[[AudioManager shareInstance] setCurAudio:newAudio];
}
});
//
dispatch_async(thread2, ^{
for (int i = 0; i < 1000; i++) {
[[AudioManager shareInstance] play];
}
});
//
dispatch_async(thread3, ^{
for (int i = 0; i < 1000; i++) {
AudioManager * audioManager = [AudioManager shareInstance];
[[AudioManager shareInstance] clearCurAudio];
}
});
}
Here is the crash EXC_BAD_ACCESS:
enter image description here
Thank you guys,problem solved!!, as #Willeke posted.
use self.curAudio rather than _curAudio.
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?
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;
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).
I am a beginner in developing iPhone applications.
I was doing this sample program below and got an error- invalid use of void expression
threadsss.h
------------
#import <Foundation/Foundation.h>
#interface threadsss : NSObject {
BOOL m_bRunThread;
int a,b,c;
}
-(void)Thread;
-(void)add;
-(void)display;
#end
threadsss.m
------------
#import "threadsss.h"
#implementation threadsss
-(void)Thread
{
m_bRunThread = YES;
NSOperationQueue* queue = [[NSOperationQueue alloc]init];
NSInvocationOperation* operation = [[NSInvocationOperation alloc]initWithTarget:self selector:#selector(display) object:nil];
[operation addDependency:[self add]];
[queue addOperation:operation];
[queue release];
}
-(void)add
{
NSLog(#"Going to add a and b!!");
a=1;
b=2;
c = a + b;
NSLog(#"Finished adding!!");
}
-(void)display
{
NSLog(#"Into the display method");
NSLog(#"The value od c is:%d",c);
}
#end
main.m
-------
#import <Foundation/Foundation.h>
#import "threadsss.h"
int main (int argc, const char * argv[]) {
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
threadsss* thread = [[threadss alloc]init];
[thread Thread];
[pool drain];
return 0;
}
I want to make an asynchronous call between the add and the display methods.After calling the display method i want to execute the add method. and in the meanwhile after printing the "I'm into the display method" the display method will wait for the add to perform its operation and the add after doing its operation will notify its completion to the display method.The display method will then print the result c.
I have tried to implement it with that in my mind.Do i need to do any other modification in my program or is the way i have implemented through dependecies is correct.
EDITED
threadss.h
-----------
#import <Foundation/Foundation.h>
#interface threadss : NSObject {
BOOL m_bRunThread;
int a,b,c;
NSOperationQueue* queue;
NSInvocationOperation* operation;
NSInvocationOperation* operation1;
NSConditionLock* theConditionLock;
}
-(void)Thread;
-(void)add;
-(void)display;
#end
threadss.m
-----------
#import "threadss.h"
#implementation threadss
-(id)init
{
if (self = [super init]) {
queue = [[NSOperationQueue alloc]init];
operation = [[NSInvocationOperation alloc]initWithTarget:self selector:#selector(display) object:nil];
operation1 = [[NSInvocationOperation alloc]initWithTarget:self selector:#selector(add) object:nil];
theConditionLock = [[NSConditionLock alloc]init];
}
return self;
}
-(void)Thread
{
m_bRunThread = YES;
//[operation addDependency:operation1];
if (m_bRunThread) {
[queue addOperation:operation];
}
//[operation addDependency:operation1];
[queue addOperation:operation1];
//[self performSelectorOnMainThread:#selector(display) withObject:nil waitUntilDone:YES];
//NSLog(#"I'm going to do the asynchronous communication btwn the threads!!");
//[self add];
//[operation addDependency:self];
sleep(1);
[queue release];
[operation release];
//[operation1 release];
}
-(void)add
{
NSLog(#"Going to add a and b!!");
a=1;
b=2;
c = a + b;
NSLog(#"Finished adding!!");
}
-(void)display
{
NSLog(#"Into the display method");
[operation1 waitUntilFinished];
NSLog(#"The Result is:%d",c);
}
#end
main.m
------
#import <Foundation/Foundation.h>
#import "threadss.h"
int main (int argc, const char * argv[]) {
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
threadss* thread = [[threadss alloc]init];
[thread Thread];
[pool drain];
return 0;
}
I made two operation queues.
But using waitUntilFinished on the same queue may lead to deadlock.How do i do the wait in display method for the add operation to complete its execution.
First, it would be easier to answer your question if you identified the line than the compiler was complaining about and showing only the relevant code. However, in this case it's pretty straight-forward. It's this line:
[operation addDependency:[self add]];
The add method returns nothing (void). And you're telling operation to add that as a dependency. What does that mean?
Either, you should change add to return self or call add on the line before:
[self add];
[operation addDependency:self];