Having got to grips a bit with the ParseKit grammar syntax (playing around in the demo app) I'm now trying to get my own mini demo working, but so far without much success. The assembler callbacks are not getting called.
Below is a condensed version of the relevant code. When testParse runs the parser seems to do it's thing OK and correctly match my string to my anything production (which also works in the demo) but didMatchAnything: is just not getting called.
#import <Foundation/Foundation.h>
#class PKParser;
#interface FileParserThing : NSObject {
PKParser* _parser;
}
- (void)testParse;
#end
#import <ParseKit/ParseKit.h>
#import "FileParserThing.h"
#interface FileParserThing ()
#property (nonatomic, retain)PKParser* parser;
- (void)didMatchAnything:(PKAssembly *)a;
#end
#implementation FileParserThing
#synthesize parser = _parser;
-(id)init
{
if (!(self = [super init])) return nil;
NSString *g = #"#start = anything; anything = Any+;";
self.parser = [[PKParserFactory factory] parserFromGrammar:g assembler:self];
return self;
}
- (void)testParse
{
NSString *s = #"Foo Bar";
NSLog(#"test parse with: %#", s);
[self.parser parse:s];
}
- (void)didMatchAnything:(PKAssembly *)a
{
NSLog(#"Hooray!");
}
#end
Digging around in the ParseKit code I can see that line 129 of PKParser
[assembler performSelector:assemblerSelector withObject:self withObject:a];
Isn't being executed, because assembler is nil. Which, in turn, leads me to the parser factory; where my understanding of what's going on begins to fail.
Disclaimer; I know, I probably need to read The Book, but one thing at a time. I want to get a small proof of concept working, before forking out 30 mice for a book I might never read again if my project is a non-starter :)
Developer of ParseKit here.
A while back I changed the signature of the Assembler callbacks to accept two arguments:
The Parser which matched the current token.
The Assembly containing the current state of the input parsing.
Previously, there had only been one argument: The Assembly.
I'm not sure the docs are fully updated to reflect this.
So I suspect that if you simply change your Assembler callback method to this, it will work:
- (void)parser:(PKParser *)p didMatchAnything:(PKAssembly *)a {
NSLog(#"%s %#", __PRETTY_FUNCTION__, a);
}
If not, let me know, and I'll help to further debug.
For background: I made this change because I ran into a situation where my Assembler callback really needed to inspect the Parser which had just made the current match.
It also aligned more closely the strong Cocoa convention of Delegate callbacks which always have the delegator object as their first argument. In hindsight I kinda wish I had renamed the whole concept of Assemblers in ParseKit to Delegates. Since in Cocoa parlance, that's basically what Assemblers are.
Related
I am trying to write a category over iTunesTrack with associated objects (an NSMutableDictionary and an NSNumber)
#import "iTunes.h"
#import <objc/runtime.h>
#interface iTunesTrack (dictionary)
- (NSMutableDictionary*) getDictionary;
- (NSNumber*) getScan;
- (BOOL)scanTrack:(NSString *)equationString;
#end
This fails:
Undefined symbols for architecture x86_64:
"_OBJC_CLASS_$_iTunesTrack", referenced from:
l_OBJC_$_CATEGORY_iTunesTrack_$_dictionary in iTunesTrack+dictionary.o
ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)
I have double checked that the Scripting Bridge framework is added and that the iTunesTrack+dictionary.m file is attached to the target. Could this be some error with combining Categories with Scripting Bridge?
Update:
If I replace iTunesTrack with SBObject, this works. I have no idea why, though.
Update 2:
This problem is reproducible:
Create new project
Add Scripting Bridge Framework and the iTunes.h header file.
Create new category of iTunesTrack with an arbitrary name
Ensure that iTunesTrack+name.h imports iTunes.h
Build
I found this page which describes using NSProxy and NSCache to store iTunesTrack objects. Would this be a better solution than trying to make a category?
Scripting Bridge is quite a mess.
The class iTunesTrack is actually called ITunesTrack under the hood.
I think they were not quite consistent with the leading lowercase i.
This is why they changed it after a while, but probably did not want to do it in the header file, to not change their API.
I don't think there is a way to fix this.
You can, however, just create the category on SBObject.
// The interface can be declared as iTunesTrack
#interface iTunesTrack (Additions)
...
#end
// The category MUST be implemented on SBObject
#implementation SBObject (Additions)
...
#end
Caution
Be aware that the category will be available on every SBObject, so make sure that all properties and methods have a unique interface.
You can't put a category on iTunesTrack (or ITunesTrack, or whatever it's called in your header) because that requires the class to exist at link time, and it doesn't: Scripting Bridge creates the target application's classes dynamically at runtime. (And they have technically arbitrary names, which is why -classForScriptingClass exists.) It's still possible to add a method to the generated class, but it means mucking about with the runtime, which is generally more trouble than it's worth. Just put your category method on SBObject and try to be careful.
NSAddict's answer pointed the way to do something I've always wanted: implementing debugQuickLookObject for SBObject types to make debugging easier. Here's the category that does iTunesTrack and iTunesArtwork.
// SBObject+Extensions.h
#import ScriptingBridge;
#interface SBObject (Extensions)
- (id)debugQuickLookObject;
#end
// SBObject+Extensions.m
#import "iTunes.h"
#implementation SBObject (Extensions)
- (id)debugQuickLookObject
{
NSString *className = self.className;
if ([className isEqualToString:#"ITunesTrack"])
{
return [self handleITunesTrack];
}
else if ([className isEqualToString:#"ITunesArtwork"])
{
return [self handleITunesArtwork];
}
return [self description];
}
- (NSString*)handleITunesTrack
{
iTunesTrack *track = (iTunesTrack *)self;
NSMutableString *s = [NSMutableString new];
[s appendFormat:#"Title: %#\n", track.name];
[s appendFormat:#"Artist: %#\n", track.artist];
[s appendFormat:#"Album: %#\n", track.album];
[s appendFormat:#"Duration: %f seconds\n", track.duration];
return s;
}
- (NSImage*)handleITunesArtwork
{
iTunesArtwork *artwork = (iTunesArtwork *)self;
NSData *data = [artwork rawData];
NSImage *image = [[NSImage alloc] initWithData:data];
return image;
}
#end
You may find the answer in this discussion:
linker command failed with exit code 1 (use -v to see invocation)
Also you can try to clean and then rebuild your project or go to Project -> Build Settings -> Valid Architectures and check whether there's all correct. Some of these advises may help you.
I want to use Protocol Buffers in an iOS project. I'm trying to avoid making the whole project into an Objective-C++ fiasco, so I want to wrap the C++ protobuf classes into Objective-C ones. I have several dozen protobuf messages, and while I have done this successfully one class at a time, ideally I would like to use inheritance to minimize the repeated code. I'm new to Objective-C and I haven't used what little I knew of C++ in 10 years, so this has mostly been an exercise in frustration. Below is an example of how I have wrapped a single message.
Code
.proto:
message MessageA {
optional string value = 1;
}
MessageAWrapper.h:
#import <Foundation/Foundation.h>
#interface MessageAWrapper : NSObject
#property (nonatomic) NSString *value;
+ (id)fromString:(NSString *)string;
- (NSString *)serialize;
#end
MessageAWrapper.mm:
#import "MessageA.h"
#import "message.pb.h"
#interface MessageAWrapper ()
#property (nonatomic) MessageA *message;
#end
#implementation MessageAWrapper
- (id)init
{
self = [super init];
if (self) {
self.message = new MessageA();
}
return self;
}
- (void)dealloc {
delete self.message;
self.message = NULL;
}
- (NSString *)value {
return [NSString stringWithUTF8String:self.message->value().c_str()];
}
- (void)setValue:(NSString *)value {
self.message->set_value([value UTF8String]);
}
- (NSString *)serialize {
std::string output;
self.message->SerializeToString(&output);
return [NSString stringWithUTF8String:output.c_str()];
}
+ (id)fromString:(NSString *)string {
MessageA *message = new MessageA();
message->ParseFromString([string UTF8String]);
MessageAWrapper *wrapper = [[MessageAWrapper alloc] init];
wrapper.message = message;
return wrapper;
}
#end
Goal
There is a lot of code here that will be repeated dozens of times in which the only variation is the wrapped class type (init, dealloc, serialize, fromString), so ideally I would like to put it on a parent ProtobufMesssage class instead. Unfortunately I've had no success in making this work because I can't find a way for the parent class to know the class its children are using, which is required for example in init and fromString.
Things I've attempted
struct
template class
void*
Obstacles I've encountered
can't find a way to store a reference to a class/type
can't have any C++ headers or code in the .h file (as this requires the whole project to be Objective-C++)
difficulty keeping references to the protobuf message parents (Message or MessageLite) because they are abstract
As I said I have very little understanding of C++ or Objective-C; most of my experience is with much higher level languages like Python and Java (though I do mostly understand basic C things like pointers).
Is this perhaps not even possible? Am I approaching it wrong or missing something obvious? Any help would be much appreciated. Thanks.
I don't know much about C++ at all, but can't you declare the Objective-C property to be a Message *?
You've already separated the C++ code from the header by declaring the property in the .mm file, the problem you will have is with instance methods named by the compiler (value() and set_value()) and only being valid methods for the subclass. It might help to use the Reflection class to get and set fields by their name. Here is an excerpt from Google's message.h showing this:
Message* foo = new Foo;
const Descriptor* descriptor = foo->GetDescriptor();
const FieldDescriptor* text_field = descriptor->FindFieldByName("text");
assert(text_field != NULL);
assert(text_field->type() == FieldDescriptor::TYPE_STRING);
assert(text_field->label() == FieldDescriptor::LABEL_OPTIONAL);
const Reflection* reflection = foo->GetReflection();
assert(reflection->GetString(foo, text_field) == "Hello World!");
You could create Objective-C -objectForKey: and -setObject:forKey: instance methods that typecheck and get or set the value (confusingly, the key in the case of MessageAWrapper would be #"value"). Your subclasses would not even need to be aware of the C++ code.
You can also separate the creator function in -init and +fromString: method into something like, +_createNewInstance;
+(Message*)_createNewInstance{ return new MessageA(); }
allowing your subclasses of MessageWrapper to reuse all code except for creating the C++ object.
While Objective C has very powerful instrospection capabilities, C++ is more limited. You do have RTTI (Run time type information), but it's not even as powerful as the Objective C counterpart.
However, it might be enough for you. Within your Objective C++ class, you might find the type of you message object with the typeid operator:
if( (typeid(self.message) == typed(foo)){
//doSomething
else if( (typeid(self.message) == typed(bar)){
// doSomething else
}
Maybe the best option is to add another indirection level. Make an Objective C class hierarchy that wraps all your protocol buffer C++ classes and then create another Objective C that uses those classes (as delegates maybe). I believe this might be a better option. Use C++ only for those unavoidable cases.
Good luck!
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.
I am attempting to build an FSM to control a timer in (iphone sdk) objective c. I felt it was a necessary step, because I was otherwise ending up with nasty spaghetti code containing pages of if-then statements. The complexity, non-readability, and difficulty of adding/changing features lead me to attempt a more formal solution like this.
In the context of the application, the state of the timer determines some complex interactions with NSManagedObjects, Core Data, and so forth. I have left all that functionality out for now, in an attempt to get a clear view of the FSM code.
The trouble is, I cannot find any examples of this sort of code in Obj-C, and I am not so confident about how I have translated it from the C++ example code I was using. (I don't know C++ at all, so there is some guessing involved.) I am basing this version of a state pattern design on this article: http://www.ai-junkie.com/architecture/state_driven/tut_state1.html. I'm not making a game, but this article outlines concepts that work for what I'm doing.
In order to create the code (posted below), I had to learn a lot of new concepts, including obj-c protocols, and so forth. Because these are new to me, as is the state design pattern, I'm hoping for some feedback about this implementation. Is this how you work with protocol objects effectively in obj-c?
Here is the protocol:
#class Timer;
#protocol TimerState
-(void) enterTimerState:(Timer*)timer;
-(void) executeTimerState:(Timer*)timer;
-(void) exitTimerState:(Timer*)timer;
#end
Here is the Timer object (in its most stripped down form) header file:
#interface Timer : NSObject
{
id<TimerState> currentTimerState;
NSTimer *secondTimer;
id <TimerViewDelegate> viewDelegate;
id<TimerState> setupState;
id<TimerState> runState;
id<TimerState> pauseState;
id<TimerState> resumeState;
id<TimerState> finishState;
}
#property (nonatomic, retain) id<TimerState> currentTimerState;
#property (nonatomic, retain) NSTimer *secondTimer;
#property (assign) id <TimerViewDelegate> viewDelegate;
#property (nonatomic, retain) id<TimerState> setupState;
#property (nonatomic, retain) id<TimerState> runState;
#property (nonatomic, retain) id<TimerState> pauseState;
#property (nonatomic, retain) id<TimerState> resumeState;
#property (nonatomic, retain) id<TimerState> finishState;
-(void)stopTimer;
-(void)changeState:(id<TimerState>) timerState;
-(void)executeState:(id<TimerState>) timerState;
-(void) setupTimer:(id<TimerState>) timerState;
And the Timer Object implementation:
#import "Timer.h"
#import "TimerState.h"
#import "Setup_TS.h"
#import "Run_TS.h"
#import "Pause_TS.h"
#import "Resume_TS.h"
#import "Finish_TS.h"
#implementation Timer
#synthesize currentTimerState;
#synthesize viewDelegate;
#synthesize secondTimer;
#synthesize setupState, runState, pauseState, resumeState, finishState;
-(id)init
{
if (self = [super init])
{
id<TimerState> s = [[Setup_TS alloc] init];
self.setupState = s;
//[s release];
id<TimerState> r = [[Run_TS alloc] init];
self.runState = r;
//[r release];
id<TimerState> p = [[Pause_TS alloc] init];
self.pauseState = p;
//[p release];
id<TimerState> rs = [[Resume_TS alloc] init];
self.resumeState = rs;
//[rs release];
id<TimerState> f = [[Finish_TS alloc] init];
self.finishState = f;
//[f release];
}
return self;
}
-(void)changeState:(id<TimerState>) newState{
if (newState != nil)
{
[self.currentTimerState exitTimerState:self];
self.currentTimerState = newState;
[self.currentTimerState enterTimerState:self];
[self executeState:self.currentTimerState];
}
}
-(void)executeState:(id<TimerState>) timerState
{
[self.currentTimerState executeTimerState:self];
}
-(void) setupTimer:(id<TimerState>) timerState
{
if ([timerState isKindOfClass:[Run_TS class]])
{
secondTimer = [NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:#selector(currentTime) userInfo:nil repeats:YES];
}
else if ([timerState isKindOfClass:[Resume_TS class]])
{
secondTimer = [NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:#selector(currentTime) userInfo:nil repeats:YES];
}
}
-(void) stopTimer
{
[secondTimer invalidate];
}
-(void)currentTime
{
//This is just to see it working. Not formatted properly or anything.
NSString *text = [NSString stringWithFormat:#"%#", [NSDate date]];
if (self.viewDelegate != NULL && [self.viewDelegate respondsToSelector:#selector(updateLabel:)])
{
[self.viewDelegate updateLabel:text];
}
}
//TODO: releases here
- (void)dealloc
{
[super dealloc];
}
#end
Don't worry that there are missing things in this class. It doesn't do anything interesting yet. I'm currently just struggling with getting the syntax correct. Currently it compiles (and works) but the isKindOfClass method calls cause compiler warnings (method is not found in protocol). I'm not really sure that I want to use isKindOfClass anyway. I was thinking of giving each id<TimerState> object a name string and using that instead.
On another note: all those id<TimerState> declarations were originally TimerState * declarations. It seemed to make sense to retain them as properties. Not sure if it makes sense with id<TimerState>'s.
Here is an example of one of the state classes:
#import "TimerState.h"
#interface Setup_TS : NSObject <TimerState>{
}
#end
#import "Setup_TS.h"
#import "Timer.h"
#implementation Setup_TS
-(void) enterTimerState:(Timer*)timer{
NSLog(#"SETUP: entering state");
}
-(void) executeTimerState:(Timer*)timer{
NSLog(#"SETUP: executing state");
}
-(void) exitTimerState:(Timer*)timer{
NSLog(#"SETUP: exiting state");
}
#end
Again, so far it doesn't do anything except announce that what phase (or sub-state) it's in. But that's not the point.
What I'm hoping to learn here is whether this architecture is composed correctly in the obj-c language. One specific problem I'm encountering is the creation of the id objects in the timer's init function. As you can see, I commented out the releases, because they were causing a "release not found in protocol" warning. I wasn't sure how to handle that.
What I don't need is comments about this code being overkill or meaningless formalism, or whatever. It's worth me learning this even it those ideas are true. If it helps, think of it as a theoretical design for an FSM in obj-c.
Thank you in advance for any helpful comments.
(this didn't help too much: Finite State Machine in Objective-C)
I suggest using State Machine Compiler, it will output Objective-C code. I have had good success in Java and Python using this.
You shouldn't be writing state machine code by hand, you should be using something to generate the code for you. SMC will generate clean clear code you can then look at if you want to learn from it, or you can just use it and be done with it.
When you use a protocol as a type-modifier, you can provide a comma-separated list of protocols. So all you need to do to get rid of the compiler warning is add NSObject to the protocol list like so:
- (void)setupTimer:(id<TimerState,NSObject>) timerState {
// Create scheduled timers, etc...
}
If you want a very simple, Objective-C implementation of a State Machine I've just released TransitionKit, which provides a well designed API for implementing state machines. It's thoroughly tested, well documented, very easy to use, and doesn't require any code generation or external tools.
I'd suggest checking out Statec it's got a nice little dsl for doing FSM and outputs ObjC code. It's sort of like mogenerator for state machines.
I am rather new at Objective-C, but I would suggest that you look at straight ANSI C implementation for the State Machine.
Just because you're using Cocoa doesn't mean you have to use Objective-C messages here.
In ANSI C, a state machine implementation can be very straightforward and readable.
My last implementation in C of a FSM specified #define STATE_x or enumerate types for the states and had a table of pointers to functions to execute each state.
Here's an odd one. I have a class named TileMap with the following interface:
#interface TileMap : NSObject
{
int *data;
int tilesWide;
int tilesHigh;
NSString *imageName;
}
+ (id)mapNamed:(NSString *)filename;
- (id)initWithFile:(NSString *)filename;
#end
The implementation looks like this:
#implementation TileMap
+ (id)mapNamed:(NSString *)filename
{
return [[self alloc] initWithFile:filename];
}
- (id)initWithFile:(NSString *)filename
{
if (self = [super init])
{
// ...
}
return self;
}
#end
But when I add a call to [TileMap mapNamed:#"map.plist"]; to my application Xcode warns:
'TileMap' may not respond to '+mapNamed:'
The application compiles fine and calls to NSLog within TileMap-initWithFile: are logged. I noticed that Xcode's syntax coloring was off for this class and method so I tried renaming both the class and the method separately. The only combination that eliminated the warning and syntax coloring issues was to rename both the class and the method.
Am I colliding with some undocumented framework class or method? Find in Documentation doesn't reveal anything. Find in Project only reveals the call, interface definition and the implementation. I'm stumped (not that it takes much). Is there a way around this without munging my existing naming conventions?
Did you #import the TileMap.h header? Did you save your TileMap.h header?
Turns out my project directory ended up with two TileMap.h and TileMap.m files—visible from the Finder but not in Xcode. One, a complete interface and implementation, in my root project directory. The other just a bare NSObject subclass in my framework subdirectory. Not sure how that happened. Deleting the latter resolved the problem. Thanks for the help just the same Dave.
Shaun,
besides the problem you asked about, you also have a memory leak in +mapNamed:. The following line returns a non-autoreleased object with a retain count of +1, which basically gives ownership to the caller:
return [[self alloc] initWithFile:filename];
According to the Memory Management Programming Guide for Cocoa, you should return autoreleased objects from convenience methods, such as this:
return [[[self alloc] initWithFile:filename] autorelease];
If you have Snow Leopard and Xcode 3.2, you might want to try running the static analyzer to find mistakes such as this one by pressing Cmd+Shift+A.