the code shown below gives an exeption
#import <Foundation/Foundation.h>
#import <AppKit/AppKit.h>
#interface Main : NSObject { }
#end
#implementation Main
+(void)main
{
NSLog(#"Hello world!");
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
NSApplication *anApplication = nil;
NSArray *screenArray = nil;
NSEnumerator *screenEnumerator = nil;
NSScreen *aScreen = nil;
NSWindowDepth *depths = null;//remove const
BOOL exactMatch = NO;
anApplication = [NSApplication sharedApplication];
screenArray = [NSScreen screens];
screenEnumerator = [screenArray objectEnumerator];
}
#end
i am using windows and please go through the link below qckapp.com/index.html?p=ObjC
you cannot done it with http://qckapp.com/index.html?p=ObjC
just go through the compiler http://www.gnustep.org
Try
#import <Cocoa/Cocoa.h>
I don't think your imports include the header for NSApplication.
That was wrong. Actually, I think the problem is that you haven't called NSApplicationMain(). It doesn't really make sense to have an application object if you don't have an application (with a user interface). If you don't want a UI, you might get away with using NSApplicationLoad().
Also make sure you are linking the AppKit framework.
your compiler does not have capabilities for ui
you just go with http://qckapp.com/index.html?p=ObjC only for basics
try gnustep
good luck.
Related
I am quite new to react native and and the bridging mechanism with native code, especially when the framework has delegates. Assume I am trying to bridge the following framework:
#protocol BRPtouchNetworkDelegate;
#class PLNetworkModule;
#interface BRPtouchNetworkManager : NSObject <NSNetServiceBrowserDelegate,NSNetServiceDelegate>
#property(retain, nonatomic) NSMutableArray* registeredPrinterNames;
#property(assign, nonatomic) BOOL isEnableIPv6Search;
- (int)startSearch: (int)searchTime;
- (NSArray*)getPrinterNetInfo;
- (BOOL)setPrinterNames:(NSArray*)strPrinterNames;
- (BOOL)setPrinterName:(NSString*)strPrinterName;
- (id)initWithPrinterNames:(NSArray*)strPrinterNames;
- (id)initWithPrinterName:(NSString*)strPrinterName;
#property (nonatomic, assign) id <BRPtouchNetworkDelegate> delegate;
#end
#protocol BRPtouchNetworkDelegate <NSObject>
-(void) didFinishSearch:(id)sender;
#end
The following is the bridge module I implemented:
RCTBRPtouchNetworkManager.h
#import <React/RCTBridgeModule.h>
#import <BRPtouchPrinterKit/BRPtouchPrinterKit.h>
#interface RCTBRPtouchNetworkManager : NSObject <RCTBridgeModule, BRPtouchNetworkDelegate>
#end
RCTBRPtouchNetworkManager.m
#import "RCTBRPtouchNetworkManager.h"
#import <BRPtouchPrinterKit/BRPtouchPrinterKit.h>
#import <React/RCTLog.h>
#implementation RCTBRPtouchNetworkManager {
BRPtouchNetworkManager *_networkManager;
}
RCT_EXPORT_MODULE();
RCT_EXPORT_METHOD(addEvent:(NSString *)name location:(NSString *)location)
{
RCTLogInfo(#"Pretending to create an event %# at %#", name, location); //a dummy method to test the bridge
}
RCT_EXPORT_METHOD(startSearchWithTimeout:(int)time) {
RCTLogInfo(#"Bridge started search with time %d", time);
_networkManager = [[BRPtouchNetworkManager alloc] init];
_networkManager.delegate = self; //I'm setting delegate here
_networkManager.isEnableIPv6Search = NO;
NSString * path = [[NSBundle mainBundle] pathForResource:#"PrinterList" ofType:#"plist"];
if( path )
{
NSDictionary *printerDict = [NSDictionary dictionaryWithContentsOfFile:path];
NSArray *printerList = [[NSArray alloc] initWithArray:printerDict.allKeys];
[_networkManager setPrinterNames:printerList];
} else {
RCTLogInfo(#"PrinterList path not found");
}
// Start printer search
[_networkManager startSearch: 5.0];
}
- (void)didFinishSearch:(id)sender {
NSLog(#"didFinishedSearch"); //this delegate method is not called
}
#end
I can easily call the dummy method and see the results in the logs. However, the delegate method didFinishSearch() is never called. I call this from javascript as follows:
componentDidMount() {
let networkManager = NativeModules.BRPtouchNetworkManager;
networkManager.startSearchWithTimeout(5.0);
}
I there something I am missing? Am I implementing delegate properly? Is this kind of functionality even possible (can't seem to not since the delegate method was used by iOS community for a long time). Your help is much appreciated.
EDIT
I found that adding the following to my bridge manager file made the delegate to fire (thanks to this post)
- (dispatch_queue_t)methodQueue
{
return dispatch_get_main_queue();
}
However, even though this solves the problem, I'd like a more technical understanding on what is going on here since I can't seem to exactly grasp it. Thank you
I know this isn’t an an answer to the post but for the bit where you’ve asked for a more technical understanding - dispatch_get_main_queue(); puts the delegate method responses on to the main thread. Since JS is single threaded any process on the background thread won’t be visible to it.
I am trying to create a plugin for Unity using Objective-C for an app running on Mac. I need to get the URL when launching my app from a link using an url protocol. I haven't used Objective-C before, so I am having trouble trying to make it work.
I am using an example provided by Unity (download example) and changing the methods to the ones I need to get the URL, but my app crashes on the line nsApplication = [[NSApplication alloc] init]; on the _GetUrl method. I have no idea what I am missing/doing wrong. Also, _GetUrl is the method called from Unity when I want to ask for the url (which is called at the first frame), but I am afraid it might be called after applicationWillFinishLaunching. So where should I actually set the delegate so that applicationWillFinishLaunching happens after the delegate is set?
I use an .h and a .m script and then compile the bundle and import it into Unity as a plugin. This is my code:
PluginUrlHandler.h
#import <Foundation/Foundation.h>
#import <AppKit/AppKit.h>
#interface NSApplicationDelegate : NSObject
{
NSString* urlString;
}
// NSApplication delegate methods
- (void)applicationWillFinishLaunching:(NSNotification *)aNotification;
- (void)handleGetURLEvent:(NSAppleEventDescriptor *)event withReplyEvent:(NSAppleEventDescriptor *)replyEvent;
//Other methods
- (NSString *)getUrl;
#end
PluginUrlHandler.m
#import <Foundation/Foundation.h>
#import "PluginUrlHandler.h"
#implementation NSApplicationDelegate
- (id)init
{
self = [super init];
urlString = #"nourl";
return self;
}
- (void)applicationWillFinishLaunching:(NSNotification *)aNotification
{
NSAppleEventManager *appleEventManager = [NSAppleEventManager sharedAppleEventManager];
[appleEventManager setEventHandler:self
andSelector:#selector(handleGetURLEvent:withReplyEvent:)
forEventClass:kInternetEventClass andEventID:kAEGetURL];
}
- (void)handleGetURLEvent:(NSAppleEventDescriptor *)event withReplyEvent:(NSAppleEventDescriptor *)replyEvent
{
[event paramDescriptorForKeyword:keyDirectObject] ;
NSString *urlStr = [[event paramDescriptorForKeyword:keyDirectObject] stringValue];
urlString = urlStr;
}
- (NSString *)getUrl
{
return urlString;
}
#end
static NSApplicationDelegate* delegateObject = nil;
static NSApplication* nsApplication = nil;
// Helper method to create C string copy
char* MakeStringCopy (const char* string)
{
if (string == NULL)
return NULL;
char* res = (char*)malloc(strlen(string) + 1);
strcpy(res, string);
return res;
}
#if c__plusplus
extern "C" {
#endif
const char* _GetUrl ()
{
if (delegateObject == nil)
delegateObject = [[NSApplicationDelegate alloc] init];
if (nsApplication == nil)
nsApplication = [[NSApplication alloc] init];
[nsApplication setDelegate:delegateObject];
return MakeStringCopy([[delegateObject getUrl] UTF8String]);
}
#if c__plusplus
}
#endif
If your application is crashing, you need to provide some information, such as a stack trace or error message so we can best help. I'm assuming the error you're receiving looks like this:
2016-03-06 10:07:14.388 test[5831:230418] *** Assertion failure in -[NSApplication init], /Library/Caches/com.apple.xbs/Sources/AppKit/AppKit-1404.34/AppKit.subproj/NSApplication.m:1980
2016-03-06 10:07:14.391 test[5831:230418] An uncaught exception was raised
2016-03-06 10:07:14.391 test[5831:230418] Creating more than one Application
You shouldn't create your own NSApplication object. Just use the system one by referencing [NSApplication sharedApplication].
Generally speaking, you shouldn't need an NSApplication (or NSApplicationDelegate) for a plugin, though. The program that's loaded you should already have one, and you don't want to mess with that. Just create a custom NSObject subclass to be your AppleEvent handler. You don't need NSApplication (or it's delegate) at all for this. Any object can be the target of an AppleEvent.
You can't use things like applicationDidFinishLaunching:withOptions: from a plugin in any case. It's too late. The application has long since launched. You'll need to add your AppleEvent handler in some function called from Unity. I'm not particularly familiar with Unity's plugin engine, so I don't know if there's a particular "load" function that gets called automatically (I don't see one in the sample code). You may have to call something yourself. It would have to occur after the plugin is loaded, but before the Get URL Apple Event happens (it's unclear what you expect to generate that).
Just curious what you're trying to pull off with this. I've never seen a protocol handler used this way.
Creation of NSApplication instance looks very suspicious. Normally you don't create it as it is a singleton by definition.
So instead of this:
if (nsApplication == nil)
nsApplication = [[NSApplication alloc] init];
you should have rather this (getting current NSApplication instance):
if (nsApplication == nil)
nsApplication = [NSApplication sharedApplication];
I made a tutorial on this, see Override app delegate in Unity for iOS and OSX (4/4) Inject code to Mach-O binary.
It uses code injection to set an Objective-C class to respond the corresponding Apple Event.
Okay. Tough to find the best starting point, here. The error XCode (4.3.2) in Lion is kicking back to me is:
Redefinition of 'a' with a different type
The author says when we declare this line (near the bottom of this page, in main)...
OwnedAppliance *a = [[OwnedAppliance alloc] init];
...that it should run fine. It doesn't. It kicks back the error above. I understand that, because OwnedAppliance has no init method in its implementation, the compiler will go up the hierarchy to OwnedAppliance's superclass, which is Appliance, and search for an init method there. It finds the overridden init, which contains only the following line...
[self initWithProductName:#"Unknown"];
...and runs that. Understood.
Ugh. Sorry, guys. I just tried to explain what I think might be happening. It took a dozen lines and I'd just scratched the surface. Rather than bore you with what I think is happening, I'll just ask:
What's going on with this code? Where does the initialization "path", for lack of a better term, end? Where does the redefinition (the error) occur?
/******************** Appliance.h ********************/
#import <Foundation/Foundation.h>
#interface Appliance : NSObject
{
NSString *productName;
int voltage;
}
#property (copy) NSString *productName;
#property int voltage;
-(id)init;
// Designated initializer
-(id)initWithProductName:(NSString *)pn;
...
#end
/******************** Appliance.m ********************/
#import "Appliance.h"
#implementation Appliance
#synthesize productName, voltage;
-(id)init
{
return [self initWithProductName:#"Unknown"];
}
-(id)initWithProductName:(NSString *)pn
{
self = [super init];
if (self) {
[self setProductName: pn];
[self setVoltage: 120];
}
return self;
...
#end
/******************** OwnedAppliance.h ********************/
#import "Appliance.h"
#interface OwnedAppliance : Appliance
{
NSMutableSet *ownerNames;
}
// Designated initializer
-(id)initWithProductName:(NSString *)pn
firstOwnerName:(NSString *)n;
...
#end
/******************** OwnedAppliance.m ********************/
#import "OwnedAppliance.h"
#implementation OwnedAppliance
-(id)initWithProductName:(NSString *)pn
firstOwnerName:(NSString *)n
{
self = [super initWithProductName:pn];
if (self) {
ownerNames = [[NSMutableSet alloc] init];
if (n) {
[ownerNames addObject:n];
}
}
return self;
}
-(id)initWithProductName:(NSString *)pn
{
return [self initWithProductName:pn
firstOwnerName:nil];
}
...
#end
/******************** main.m ********************/
#import <Foundation/Foundation.h>
#import "Appliance.h"
#import "OwnedAppliance.h"
int main(int argc, const char * argv[])
{
#autoreleasepool {
// Previously omitted problematic code:
Appliance *a = [[Appliance alloc] init];
NSLog(#"a is %#", a);
[a setProductName:#"Washing Machine"];
[a setVoltage:240];
NSLog(#"a is %#", a);
// The following line is where the error occurs:
OwnedAppliance *a = [[OwnedAppliance alloc] init];
...
}
return 0;
}
I've thought a lot about this question and how to ask it. I don't think it's a terribly dumb one. :) But my brain is fried from 9 hours of studying this stuff, so I apologize if this is a totally obvious question. TIA
EDIT: main() now contains the code that was actually causing the error. Thanks to Jacques for being good enough to catch it despite the omission.
The compiler's actually telling you that the variable itself, a, has been declared twice; the error has nothing to do with the assignment. Somehwhere else, in scope, you have another variable named a, which has a different type than OwnedAppliance *. Change the name(s) of one (or both) and the error will go away.
I'm pretty new to cocoa and Xcode, I've done some basic C coding, but I pretty much suck at objective-c and cocoa, so please excuse me for any stupid mistakes I make. My problem is with these global variables I'm using.
I have a global NSString variable declared in the header file, and it's used in the main file like so:
//AppController.h
-(IBAction)button1:(id)sender;
-(IBAction)button2:(id)sender;
extern NSString *hi
//AppController.m
-(IBAction)button1:(id)sender
{
NSString *const hi = #"Hello";
}
-(IBAction)button2:(id)sender;
{
NSLog (#"%#", hi);
}
However when I click run the build fails and I get the error message:
"_hi", referenced from:
Some extra info:
Undefined symbols for architecture x86_64: "_hi", referenced from: -[AppController gallery:] in AppController.o
ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)
If you know what this means and/or how to fix it please help me. Thanks
You need to provide a global definition for hi. Move your declaration:
NSString *const hi = #"Hello";
to someplace outside of any method. I'm not really sure what you want button1: to do, but it doesn't seem necessary at all for your implementation.
I assume Luke likes to:
Set the string to a specific value after button one is clicked,
and retrieve it again after button two is clicked.
AppController.h
#import <Cocoa/Cocoa.h>
#interface AppController : NSObject{
NSString * string;
}
-(IBAction)button1:(id)sender;
-(IBAction)button2:(id)sender;
#end
AppController.m
#import "AppController.h"
#implementation AppController
-(IBAction)button1:(id)sender
{
string = #"Hello";
}
-(IBAction)button2:(id)sender;
{
NSLog (#"%#", string);
}
#end
When defining global variables and constant strings, etc., this is usually how I do it:
MDAppController.h:
#import <Cocoa/Cocoa.h>
extern NSString * const MDShouldShowInspectorKey;
extern NSString * const MDShouldShowViewOptionsKey;
extern BOOL MDShouldShowInspector;
extern BOOL MDShouldShowViewOptions;
#interface MDAppController : NSObject <NSApplicationDelegate> {
IBOutlet NSWindow *window;
}
- (IBAction)hideInspector:(id)sender;
#end
MDAppController.m:
#import "MDAppController.h"
NSString * const MDShouldShowInspectorKey = #"MDShouldShowInspector";
NSString * const MDShouldShowViewOptionsKey = #"MDShouldShowViewOptions";
BOOL MDShouldShowInspector = NO; // default value
BOOL MDShouldShowViewOptions = YES; // default value
#implementation MDAppController
+ (void)initialize {
NSMutableDictionary *defaultValues = [NSMutableDictionary dictionary];
[defaultValues setObject:
[NSNumber numberWithBool:MDShouldShowInspector]
forKey:MDShouldShowInspectorKey];
[defaultValues setObject:
[NSNumber numberWithBool:MDShouldShowViewOptions]
forKey:MDShouldShowViewOptionsKey];
[[NSUserDefaults standardUserDefaults] registerDefaults:defaultValues];
}
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification {
NSUserDefaults *uD = [NSUserDefaults standardUserDefaults];
MDShouldShowInspector = [[uD objectForKey:MDShouldShowInspectorKey] boolValue];
MDShouldShowViewOptions = [[uD objectForKey:MDShouldShowViewOptionsKey] boolValue];
}
- (IBAction)hideInspector:(id)sender {
NSLog(#"MDShouldShowViewOptionsKey == %#", MDShouldShowViewOptionsKey);
MDShouldShowInspector = NO;
[[NSUserDefaults standardUserDefaults]
setObject:[NSNumber numberWithBool:MDShouldShowInspector]
forKey:MDShouldShowInspectorKey];
}
#end
My question is why do you want to be extern? The best way here is to create a singleton, you should have all members as part of a class and avoid any global.
Hope this helps
I am just learning how to use ScriptingBridges. I made a method that slowly fades the volume on iTunes, and would like to make it a category so I can do the following:
iTunesApplication* iTunes = [SBApplication applicationWithBundleIdentifier:#"com.apple.iTunes"];
[iTunes lowerVolume:50 speed:1];
I made another category for NSSpeechSynthesizer that works, but I can't get this one to. I keep getting the following build error:
"_OBJC_CLASS_$_iTunesApplication", referenced from:
l_OBJC_$_CATEGORY_iTunesApplication_$_iTunesApplicationAdditions in iTunesApplication.o
objc-class-ref-to-iTunesApplication in iTunesApplication.o
ld: symbol(s) not found
collect2: ld returned 1 exit status
Is there something special I can do to make it work since I can't include the symbols?
Thanks,
Ryan Pendleton
UPDATE:
I only found one solution, which is below. It involves MethodSwizzling, so I'm open to better answers, but for now it's all I have.
The solution I found was to use the Objective-C runtime API. I'm sure there's a better way to organize this, but here's how I did it:
Here are my .h and .m files for creating the category. Notice how lowerVolume is not an actual method, but a C function with the arguments id self, and SEL _CMD. You'll also notice a setupCategories function. We'll call that later.
// iTunes+Volume.h
#import <objc/runtime.h>
#import "iTunes.h"
void lowerVolume(id self, SEL _cmd, int dest, float speed);
void setupCategories();
#interface iTunesApplication (Volume)
- (void)lowerVolume:(int)dest speed:(float)speed;
#end
// iTunes+Volume.m
#import "iTunes+Volume.h"
void lowerVolume(id self, SEL _cmd, int dest, float speed)
{
NSLog(#"Lower Volume: %i, %f", dest, speed);
}
void setupCategories()
{
id object = [[SBApplication alloc] initWithBundleIdentifier:#"com.apple.iTunes"];
Class class = [object class];
[object release];
class_addMethod(class, #selector(lowerVolume:speed:), (IMP)lowerVolume, "#:if");
}
Now that I've made the functions, I need to actually add them to the scripting bridge class using the Objective-C runtime API. I'll do this in main.m to make sure that the methods are ready to be used when the run loop starts.
// main.m
#import <Cocoa/Cocoa.h>
#import "iTunes+Volume.h"
int main(int argc, char *argv[])
{
NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
setupCategories();
return NSApplicationMain(argc, (const char **) argv);
[pool drain];
}
Now, I can use my method wherever I want as long as I include the header files:
- (void)mute
{
iTunesApplication* iTunes = [[SBApplication alloc] initWithBundleIdentifier:#"com.apple.iTunes"];
[iTunes lowerVolume:0 speed:1];
[iTunes release];
}
If any of this doesn't make sense, just tell me and I'll try to explain it better.
I think you need to include -framework ScriptingBridge to your gcc arguments. That got it to compile for me!
As noted above, you can't easily do a category on iTunesApplication because it doesn't exist at compile time, and also because the runtime class name is ITunesApplication (capital "I").
The best solution I've found is to do your category on the class that DOES exist, SBApplication. Here's the code I tested that works and does what the original example was trying to do:
// SBApplication+Extensions.h
#import ScriptingBridge;
#interface SBApplication (Extensions)
- (void)lowerVolume:(int)dest speed:(float)speed;
#end
// SBApplication+Extensions.m
#import "iTunes.h"
#import "SBApplication+Extensions.h"
#implementation SBApplication (Extensions)
- (void)lowerVolume:(int)dest speed:(float)speed
{
NSLog(#"Lower Volume: %i, %f", dest, speed);
}
#end
// Caller, say in AppDelegate
#import "SBApplication+Extensions.h"
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
{
iTunesApplication *iTunesApp =
[SBApplication applicationWithBundleIdentifier:#"com.apple.iTunes"];
[iTunesApp lowerVolume:4 speed:3.3f];
}