Threading in Objective C - objective-c

I am new to Objective-C and i was trying out a sample program in Threads from the book "Learn Objective-C for java developers".
I am getting 6 errors on the function definition.
Its with errors.
Is there any link that gives good threading example for beginners like me.
Thread2.m
#import <Foundation/Foundation.h>
#import "Process.h"
int main (int argc, const char * argv[]) {
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
Process* process = [Process new];
NSProgressIndicator* indicator = [NSProgressIndicator new];
Heartbeat* heartbeat = [Heartbeat startHeartbeatProcess:process withIndicator:indicator];
[heartbeat stop];
[pool drain];
return 0;
}
Process.h
#import <Foundation/Foundation.h>
#interface Process : NSObject {
}
#property double progress;
#end
#interface NSProgressIndicator : NSObject {
}
#end
#interface Heartbeat : NSObject {
#public
NSThread* thread;
NSProgressIndicator* indicator;
Process* monitor;
}
+(Heartbeat*)startHeartbeatProcess:(id)process withIndicator:(NSProgressIndicator*)progress;
-(void)stop;
-(void)heartbeatThread:(id)ignored;
-(void)updateIndicator;
#end
Process.m
#import "Process.h"
#implementation Process
+(Heartbeat*)startHeartbeatProcess:(id)process withIndicator:(NSProgressIndicator*)progress {
Heartbeat* heartbeat = [Heartbeat new];
heartbeat->monitor = process;
heartbeat->indicator = progress;
heartbeat->thread = [[NSThread alloc]initWithTarget:heartbeat selector:(heartbeatThread:) object:nil]; //'heartbeatThread' undeclared
[heartbeat->thread start];
return heartbeat;
}
-(void)stop {
[thread cancel]; //thread undeclared
}
-(void)heartbeatThread:(id)ignored {
while (![thread isCancelled]) {
//thread undeclared
[self performSelectorOnMainThread:#selector(updateIndicator) withObject:nil waitUntilDone:YES];
[NSThread sleepForTimeInterval:0.5];
}
}
-(void)updateIndicator {
[indicator setDoubleValue:monitor.progress];
}
#end
Could not find the setDoubleValue method in the class NSProgressIndicator.

Could not find the setDoubleValue method in the class NSProgressIndicator
For this one, that's because NSProgressIndicator is part of AppKit (the Cocoa GUI library), and you're only linking against Foundation (which is the non-GUI stuff). It seems in your code you've attempted to define an interface for NSProgressIndicator yourself, but you haven't declared any methods on it — that's why it's complaining about not being able to find the setDoubleValue method.
What should you do about it? Well, if you're wanting to use Cocoa's GUI stuff, you need to structure your program in the way Cocoa's GUI system expects. In Xcode, if you create a new Cocoa application it should give you a sample project to build on. In particular, your main() function should contain return NSApplicationMain(argc, (const char **) argv);, which handles starting a run loop to receive events.
If you just want to learn about threading, it may be better to abandon trying to get GUI stuff in the same program, and adapt your code to just print stuff to the console instead.
I find it hard to believe that this is an example from a book, since it seems fairly fundamentally broken!
Other errors I found when I tried running it:
Expected ')' before ':' token
This is on the line heartbeat->thread = [[NSThread alloc]initWithTarget:heartbeat selector:(heartbeatThread:) object:nil];.
The problem there is the syntax for declaring a selector: instead of just saying selector:(heartbeatThread:), you need to say selector:#selector(heartbeatThread:).
'thread' undeclared (first use in this function'
In your header file, you claimed that the class Heartbeat has a method called stop. (That is, you defined -(void)stop; in the #interface section for the Heartbeat class).
However, you implemented that method in the #implementation section for the Process class.
You'd make it easier for yourself if you had one pair of .h and .m files per class, rather than trying to cram multiple class definitions into a single pair of files. That way you could make sure you were putting the implementation of the stop method in the correct class's .m file.
property 'progress' requires method '-progress' to be defined - use #synthesize, #dynamic or provide a method implementation
In the implementation for process you defined an #property called progress. If you define a property, you either have to write getters and setters for it yourself, or write #synthesize progress within your implementation. Doing the latter is equivalent to Objective-C generating your getters and setters automatically at runtime.

thread is not a member of the Process class; it belongs to the Heartbeat class. You have to define a member in the Process class to keep a reference on the Heartbeat instance so you can call methods on its thread member.

Related

implementing one method from another in Objective-C, combining plugins

I'm trying to combine two plugins written in Objective-C. I have Plugin1 and Plugin2 which execute fine enough independently. I'm trying to add the Plugin2.m code to my Plugin1 Classes folder and execute both at the same time.
When I do this, Plugin1.m seems to execute first, I guess because it has IBAction calls and Plugin2.m doesn't? This is fine, but I'd like to run Plugin2.m within a function in Code1.m. So In the code below, when the IBAction call in Plugin1 is initiated I would like it to do what Plugin2 normally does and then continue with Plugin1 methods.
Plugin1.h:
#import Plugin2.h
#interface Plugin1: NSWindowController {
...
}
+(void) Plugin2;
#end
Plugin1.m:
#import "Plugin1.h"
#import "Plugin2.h"
#implementation Plugin1
-(id) loadPlugin1
{
...
}
-(IBAction) computeStuff:(id)sender
{
[self Plugin2];
//Plugin2* testRun = [Plugin2 alloc] init];
...do other stuff
}
#end
Plugin2.h
#interface Plugin2 : PluginFilter {
...
}
#end
Plugin2.m:
#import Plugin2.h
#implementation Plugin2
-(void) initPlugin
{
...
}
#end
Unfortunately I can't troubleshoot this from within Xcode, I have to install and test the plugin on my program to test. But when I keep an eye on Console and try the above I get "-[Plugin1 Plugin2]: unrecognized selector sent to instance 0x7....
in your plugin1 interface you defined
+(void)plugin2;
but implemented no method
+(void)plugin2 {
}
when you invoke + method you need to tell which class you call the method from because self refers to an object and not the class.
[self.class plugin2];
// OR
[Plugin1 plugin2];
Hints: try to follow naming conventions in objective-c.
This will help you distinguish if a definition is a -method: or Class
Consider reading about delegate design patterns and the use of <Protocols>
Also define special -initPlugin in your Plugin2 implementation and use a return type. Otherwise you initialise nothing.
-(instancetype)initPlugin;

Programmatically creating new instance method to track message sending

I want to design a class (TrackingClass) that would be in charge of tracking the calls to some methods of an other class (TrackedClass), i.e. of setting up the method swizzling from what I understood.
So let's say I load up an array with #selectors of the instance methods of TrackedClass i'm interested in.
Here is the pseudo-code I would like to run :
#implementation BCTrackedClass
-(void)doA
{
}
#end
and
#implementation BCTrackingClass
#import "BCTrackingClass.h"
#import "BCTrackedClass.h"
#include <objc/runtime.h>
#include <objc/objc-runtime.h>
#implementation BCTrackingClass
void myMethodIMP(id self, SEL _cmd);
void myMethodIMP(id self, SEL _cmd)
{
//NSLog(#"_cmd : %#",NSStringFromSelector(_cmd));
[BCTrackingClass logCallForMethod:NSStringFromSelector(_cmd)];
objc_msgSend(self,
NSSelectorFromString([NSString stringWithFormat:#"tracked%#",NSStringFromSelector(_cmd)]));
}
+(void)setUpTrackingForClass:(Class)aClass andMethodArray:(NSArray*)anArray //Array of selectorsStrings of methods to track
{
for (NSString* selectorString in anArray)
{
SEL selector = NSSelectorFromString(selectorString);
SEL trackedSelector = NSSelectorFromString([NSString stringWithFormat:#"tracked%#",selectorString]);
class_addMethod(aClass,
trackedSelector,
(IMP) myMethodIMP, "v#:");
//Swizzle the original method with the tracked one
Method original = class_getInstanceMethod(aClass,
selector);
Method swizzled = class_getInstanceMethod(aClass,
trackedSelector);
method_exchangeImplementations(original, swizzled);
}
}
+(void)logCallForMethod:(NSString*)aSelectorString
{
NSLog(#"%#",aSelectorString);
}
#end
Theoretically, I'm just missing the bit of code where I could effectively create this new instance method trackedSelector. Can I achieve that ?
Edit
I updated the code with some new piece of information, am I getting closer ?
Edit 2
I set up a Github repository with a Demo application if people want to dynamically try out their ideas.
Source : BCTrackingClass on Github
Edit 3
I finally come up with a working version of the code (cf Github repo, or just above). My next problem is : I want my class to be instance based (currently, all my methods are class methods), so that I can assign a property #property NSMutableDictionnary* to instances of the class for call logging.
I'm not sure how to achieve that. Any ides ?
Do you want to do it for all instances of all objects of that class?
for some selectors or all of them?
...
If what you want is to track specific instances, then the simplest route is to use isa swizzling, doing that, more or less (the code is absolutely untested)
#interface ClassTracker
+ (void)trackObject:(id)object;
#end
static const char key;
#implementation ClassTracker
+ (void)trackObject:(id)object
{
objc_setAssociatedObject(object, &key, [object class], OBJC_ASSOCIATION_ASSIGN);
object_setClass(object, [ClassTracker class]);
}
- (NSMethodSignature *)methodSignatureForSelector:(SEL)sel
{
Class aClass = objc_getAssociatedObject(self, &key);
return [aClass instanceMethodSignatureForSelector:sel];
}
- (void)forwardInvocation:(NSInvocation *)invocation
{
Class aClass = objc_getAssociatedObject(self, &key);
// do your tracing here
object_setClass(self, aClass);
[invocation invoke];
object_setClass(self, [ClassTracker class]);
}
// dealloc is magical in the sense that you really want to undo your hooking
// and not resume it ever!
- (void)dealloc
{
Class aClass = objc_getAssociatedObject(self, &key);
object_setClass(self, aClass);
[self dealloc];
}
#end
If it's used for reverse engineering or debug purposes, that should (with minor adaptations) do the trick.
If you intend that to be fast, then you have to do instance method swizzling, knowing their type and so forth.
My "solution" has the drawback that it will only trace entering calls, IOW if a selector calls other ones, since the isa swizzling is paused to recurse the call, then you don't see the new ones until you restore the isa swizzling.
There may be a way to forward the invocation to the original class, without undoing isa swizzling, but I reckon I was too lazy to search for it.

Release method not recognized at runtime (non Cocoa)

I'm a newbie to Objective-C but have extensive experience in C and C++. The first thing I have noticed is that there is a real void in basic tutorials out there as all assume you are developing for the iPhone or Mac and using Cocoa. I'm not using Cocoa or Gnustep. To the point:
As a simple example to get started I'm trying to wrap the C's File I/O functionality. My code starts as
File.h
#include <objc/Object.h>
#include <stdio.h>
#interface File:Object
{
FILE *pFile;
char *path;
}
#property FILE *pFile;
#property char *path;
- (void)new;
- (void)OpenReadText:(const char*)var1;
- (void)release;
#end
And File.m
#include "File.h"
#implementation File
#synthesize pFile, path;
- (void)new
{
self = [super init];
}
- (void)release
{
fclose(pFile);
[super release];
}
- (void)OpenReadText:(char*)var1
{
path = var1;
pFile = fopen(path,"r");
}
#end
Then main.m
#include <stdio.h>
#import <objc/Object.h>
#include "File.h"
int main(void) {
File *Fileobj = [File new];
[Fileobj OpenReadText:"File.h"];
[Fileobj release];
}
The compiler gives me a warning that my object "may not respond to '-release'". Then when running the program is results in a runtime error: "does not recognize release. This application has requested the Runtime to terminate" .. and so on.
I'm guessing I'm making a simple newbie error, but where? Or perhaps there is something missing? I'm hoping someone can point me in the right direction here. Thanks.
If this qst has been asked already then a reference would do too. I did try to find a reference but no luck.
FOLLOW UP:
changed release method to
- (void)release
{
fclose(pFile);
[super free];
}
and it appeared to work. Apparently free is recognized in object.h.
As others have said it is unusual to use Objective-C without the Foundation frameworks. However, the Object class should implement release, retain etc. The Object class included (but not used) in Apple's Objective-C Runtime certainly contains these basic methods.
Assuming your Object class does contain these basic methods there are a couple of problems with your class as implemented.
First, you have created a new instance method which simply calls [super init]. The new method by convention is a class method which is shorthand for calling alloc and init to create and initialise an object. new is defined in Apple's Object class. It is implemented as:
+ (id)new
{
id newObject = (*_alloc)((Class)self, 0);
Class metaClass = self->isa;
if (class_getVersion(metaClass) > 1)
return [newObject init];
else
return newObject;
}
Note that this method is a class method, signified by the + instead of the -. GNUStep implements new as follows:
+ new
{
return [[self alloc] init];
}
The idiomatic way to use new would be:
File *obj = [File new];
This is in fact what you have done, however, this is calling the class method new not your instance method new.
If you wanted to call your new method you'd have to call:
File *obj = [[File alloc] new];
but as others have stated you'd need to return your object. Removing your new method would have no effect on your implementation as it isn't currently being called.
Secondly, you have placed your call to fclose in your overriden release method. This is wrong, certainly in Apple's implementation of Object anyway, GNUstep appears to be different. release could get called multiple times on a single instance of an object. retain and release are used to increment/decrement the objects retain count. Only when the retain count reaches zero should the file handle be closed. Normally, within Foundation you'd place the call to fclose in a dealloc method. dealloc is Objective-C's destructor method. The dealloc should look something like:
- (void)dealloc
{
fclose(pFile);
[super dealloc];
}
However, dealloc doesn't appear to be implemented in either Apple's or GNUstep's Object class. There is, as you point out in your question a free method which seems to be a destructor.
It would appear that replacing the above dealloc method with an equivalent free method would work as a destructor, e.g.:
- (void)free
{
fclose(pFile);
[super free];
}
Apple's implementation of Object contains retain and release methods but the GNUstep implementation does not. Neither implementation contains a dealloc method.
The implementations of Object.m and NSObject.m for Apple and GNUstep can be found at the following locations:
Apple Object.m: http://opensource.apple.com/source/objc4/objc4-532.2/runtime/Object.m
GNUstep Object.m: https://github.com/gnustep/gnustep-libobjc/blob/master/Object.m
Apple NSObject.mm: http://opensource.apple.com/source/objc4/objc4-532.2/runtime/NSObject.mm
GNUstep NSObject.m: https://github.com/gnustep/gnustep-base/blob/master/Source/NSObject.m
Is release defined on class Object? If it is not, then your call to
[super release];
will not work. (In cocoa, release is a member of NSObject; your Object class may or may not have it, and in fact the retain/release reference counting might not be there at all.)
You should confirm that your base class includes all methods called via super.
As #xlc0212 pointed out, the reference counting style of memory management is included in NSObject.
NSObject is a part of CoreFoundation library for Cocoa, CocoaTouch and GnuStep. I would say you need to link to CoreFoundation.
One book that I've read and focuses on pure Objective-C (not necessarily Cocoa) is "Programming in Objective-C 2.0" by Steven G Kochan.

Writing my own block method

I am trying to follow through examples from other as well as Apple. I'm lost.
I have a singleton class that I use to handle my user logging in (challenges a web server, etc.).
I want to create a block I can call, pass in the username/password. The block will perform the web service calls then return if it was successful or not.
This is what i've manage to get working so far:
My singleton class looks like this:
.h
typedef void (^AMLoginBlock)(NSString *userName, NSString *password);
#interface AuthManager : NSObject
+ (id)sharedManager;
+ (bool)loginUserWithBlock:(AMLoginBlock)block;
#end
.m
#implementation AuthManager
+ (id)sharedManager
{
static dispatch_once_t pred = 0;
__strong static id _sharedObject = nil;
dispatch_once(&pred, ^{
_sharedObject = [[self alloc] init]; // or some other init method
});
return _sharedObject;
}
+ (bool)loginUserWithBlock:(AMLoginBlock)block {
NSLog(#"im printing from AM");
return true;
}
#end
I then call the method like so:
bool rtn = [AuthManager loginUserWithBlock:^(NSString *userName, NSString *password) {
NSLog(#"im here in the block LVC.");
}];
My question is three parts:
How do I write a completion handler for the block similar to UIView animation... block.
Is it a good idea to perform these web service calls from a block based implementation?
Should I be declaring the block method like so:
- (bool)loginUserWithBlock:(AMLoginBlock)block;
instead of using +(bool)loginUser.. since it is in a singleton class. Not sure if this will cause multiple instances of the singleton to be created.
My goal is to be able to call this block like you call [UIView animation..]. So I can simply do:
[AuthManager loginUserWithUsername:foo
password:bar1
completion:^(BOOL finished) {
if (finished)
//push new view controller.
else
//spit out error
}];
Completion Handler
You will want to copy the completion block to a class iVar:
#property (nonatomic, copy) void (^completionHandler)(bool *);
Because you are saving the block, you need to have a non-class method take the block (see following for how to do this without violating your singleton). An example of your method could be:
- (void)loginUserWithUsername:(NSString *)username
password:(NSString *)password
completion:(void(^)(bool *finished))completionBlock
{
// Copy the blocks to use later
self.completionHandler = completionBlock;
// Run code
[self doOtherThings];
}
Then when your login code has finished its work, you can call the block - here I pass self.error, a bool to the block :
- (void)finishThingsUp
{
// We are done with all that hard work. Lets call the block!
self.completionHandler(self.error);
// Clean up the blocks
self.completionHandler = nil;
}
Good Idea
Well, this is a philosophical question, but I will say this: Blocks in Objective-C allow you to write code that performs a single task and easily integrate it into many programs. If you chose to not use a completion handler in your login code you would need your login code to:
Require that classes using it implement a protocol (as in a LoginDelegate)
Use some other system of informing your code such as Key Value observing or Notifications
Hard code it to only work with one type of calling class
Any of the above approaches are fine, I feel a block-based call back system is the simplest and most flexible. It allows you to just use your class without worrying about additional infrastructure (setting up notifications, conforming to protocols, etc. ) while still letting you reuse it in other classes or programs.
Singelton
Methods that begin with a + in Objective-C are class methods. You cannot use class methods to manipulate iVars, as who would own that data?
What you can do is have a class method that always returns the same instance of that class, allowing you to have an object that can own data, but avoid ever having more than one of them.
This excellent Stack Overflow answer has sample code.
Good Luck!

Warning in ITunesFinder example (Apress - Learning Obj-C)

When I compile the code below I get the following warning: Incompatible type sending "ITunesFinder *" expected "id"? I am only just starting out and to be truthful am a little confused by this example. I would be interested to know if there is a way to write this example without using the delegate class?
I am also a little confused by the class implementation, the book does not describe what this is based on, or for that matter what Categories, Protocols or Delegates do, nor how they work.
here is the code ...
// INTERFACE
#import <Cocoa/Cocoa.h>
#interface ITunesFinder : NSObject
#end
.
// IMPLEMENTATION
#import "ITunesFinder.h"
#implementation ITunesFinder
-(void) netServiceBrowser: (NSNetServiceBrowser *) b
didFindService: (NSNetService *) service
moreComing: (BOOL) moreComing {
[service resolveWithTimeout:10];
NSLog(#"Service Found: %#", [service name]);
}
-(void) netServiceBrowser: (NSNetServiceBrowser *) b
didRemoveService: (NSNetService *) service
moreComing: (BOOL) moreComing {
[service resolveWithTimeout:10];
NSLog(#"Service Lost!: %#", [service name]);
}
#end
.
// MAIN
#import <Foundation/Foundation.h>
#import "ITunesFinder.h"
int main (int argc, const char * argv[]) {
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
NSNetServiceBrowser *browser = [[NSNetServiceBrowser alloc] init];
ITunesFinder *finder = [[ITunesFinder alloc] init];
NSLog(#"iTunesFinder ... Start");
[browser setDelegate: finder]; // <<< Warning here !!!!
[browser searchForServicesOfType: #"_daap._tcp" inDomain:#"local."];
NSLog(#"Browsing ...");
[[NSRunLoop currentRunLoop] run];
// Clean up
[browser release];
[finder release];
[pool drain];
return 0;
}
any pointers / wisdom would be much appreciated.
gary
When I tried compiling this under 10.6 with gcc 4.2.1, it compiled with the following warning:
main.m:12: warning: class 'ITunesFinder' does not implement the 'NSNetServiceBrowserDelegate' protocol
I suspect this is the same issue you describe, but with a more descriptive diagnostic coming from the compiler (maybe a more recent version than yours?). You can address this warning by adding the protocol to the interface declaration in the header:
#interface ITunesFinder : NSObject<NSNetServiceBrowserDelegate>
The reason the warning was issued is that the setDelegate: method has the following signature:
- (void)setDelegate:(id <NSNetServiceBrowserDelegate>)delegate;
which simply means it can take any object that implements the formal NSNetServiceBrowserDelegate protocol. Since your class interface didn't explicitly declare this, the compiler warns you of the fact. It should still work at runtime, provided the actual methods are provided when the delegate messages are actually sent.
is it possible to write this example without using the delegate class?
No, the delegate class is the way you receive event notifications.
I am also a little confused by the class implementation, the book does not describe what this is based on, or for that matter what Categories, Protocols or Delegates do, nor how they work.
The NSNetServiceBrowserDelegate protocol defines a set of methods that your class needs to implement. You can think of it just like an interface in Java or a virtual base class in C++. The difference in Objective-C (which doesn't support multiple inheritance) is that you don't inherit from the interface you are trying to implement, you merely declare the fact that your particular class implements these methods according to the protocol.
Now protocols are used for a variety of things, and a very common pattern in Cocoa is to use them for callbacks. So here, your ITunesFinder is implementing the browser protocol in a way such that the NSNetServiceBrowser knows how to call your class (which it has never seen before!) in order to provide browser notifications.
These delegates are often used to delegate behaviour from a framework class to one of your classes, to allow you to easily customise things without lots of subclassing, and to receive notifications of events (typically before and after something interesting). It's a very elegant model.
The Apple documentation is very good on this subject:
Basics of Protocols
Objective-C Protocols
Cocoa delegates