Class methods in main loop? - objective-c

I have some class methods from the ViewController class that are activated with BOOL Types. I want to insert those methods into the main loop so when they BOOL's are activated the method will run, but for some reason i can't get the viewController methods in to main.
But I'm getting an error for the method call and the method isn't showing up in auto complete.
#import <UIKit/UIKit.h>
#import "AppDelegate.h"
#import "ViewController.h"
int main(int argc, char *argv[])
{
#autoreleasepool
{
[ViewController singleBoxShow];
return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
}
}

This is the wrong place for that. The view hierarchy isn't even close to existing yet there. Don't mess with main() without a very good reason.
Instead this should go in the callbacks of the ApplicationDelegate. Such as applicationDidFinishLaunchWithOptions:.

Related

Trouble with calling a method in Objective C (Apple Documentation example)

I'm following along with Apple's "Programming with Objective C" document, the link being: https://developer.apple.com/library/ios/documentation/Cocoa/Conceptual/ProgrammingWithObjectiveC/WorkingwithObjects/WorkingwithObjects.html#//apple_ref/doc/uid/TP40011210-CH4-SW1
Anyways, I've gotten to the point where it ask for calling the sayHello method.
"Create a new XYZPerson instance using alloc and init, and then call the sayHello method."
#import <Foundation/Foundation.h>
#import "XYZPerson.h"
int main(int argc, const char * argv[]);
XYZPerson *firstPerson = [[XYZPerson alloc] init]; //Initializer element is not a lime-time constant
[firstPerson sayHello]; //No Visible #interface for 'XYZPerson' delcares the selector 'sayHello'
#implementation XYZPerson
- (void)sayHello {
[self saySomething:#"Hello, World"];
}
- (void)saySomething: (NSString *)greeting {
NSLog(#"%#", greeting);
}
#end
I believe I'm having a misunderstanding with how apple is explaining the work or just have no clue.
Wishing apple had these examples done for us to review over.
You need to put the code inside the main function. Right now you have the code just sitting in your file, outside of any function. It should be:
int main(int argc, const char * argv[]) {
XYZPerson *firstPerson = [[XYZPerson alloc] init];
[firstPerson sayHello];
}
Also, according to the docs you should have a separate main.m file that has your main function inside of it.
As you can only access public functions which are declared in .h file with the class object.
Kindly declare that function in .h file and it will solve your problem

Unable to instantiate the UIApplication subclass instance

i'm building a SpriteBuilder project and getting the error of:
" * Assertion failure in int UIApplicationMain(int, char **, NSString *, NSString *)(), /SourceCache/UIKit_Sim/UIKit-2903.23/UIApplication.m:2380
Unable to instantiate the UIApplication subclass instance. No class named NSApplication is loaded."
For the main.m code of:
#import <UIKit/UIKit.h>
int main(int argc, char *argv[]) {
#autoreleasepool {
int retVal = UIApplicationMain(argc, argv, nil, #"AppController");
return retVal;
}
}
What's the cause?
XCode is referring to the wrong info.plist file. In Build Settings, the info.plist path should be "Source/Resources/Info.plist" instead of "$(SRCROOT)/Source/libs/cocos2d-iphone/external/Chipmunk/xcode/main-Info.plist". Changing the path fixed it.

Accessing interface method defined in .m file

MyClass.h file
#import <Foundation/Foundation.h>
#interface MyClass : NSObject
{
// This is the Place of Instance Variable
}
- (void)thePublicMethod;
#end
MyClass.m file
#import "MyClass.h"
#interface MyClass()
- (void)thePrivateMethod;
#end
#implementation MyClass
-(void)thePublicMethod {
NSLog(#"Public Method Called");
}
- (void)thePrivateMethod {
NSLog(#"Private Method Called");
}
#end
The main.m file
#import <Foundation/Foundation.h>
#import "MyClass.h"
int main(int argc, const char * argv[])
{
#autoreleasepool {
MyClass *myObj = [[MyClass alloc] init];
[myObj thePublicMethod];
// [myObj thePrivateMethod];
}
return 0;
}
since “Private” methods can be created by defining them in a class’s implementation file while omitting them from its interface file.
i want to access thePrivateMethod from main.m and also can i call thePrivateMethod() from thePublicMethod() is it possible and how ?
If you want to access an internal method from somewhere other than the class's implementation, then you need to truly declare it as a private method.
Move that class extension to its own header file, say MyClass_Private.h. Then #import that header into both main.m and MyClass.m.
I.e. move this:
#interface MyClass()
- (void)thePrivateMethod;
#end
Into a file called MyClass_Private.h and then #import "MyClass_Private.h" in both your MyClass.m and main.m files.
Internal means only used in the innards of this framework or class.
Private means may be used by this framework or the class, but may be exposed to clients that are more intimately tied to the class than through Public API. Typically reserved for framework authors on large scale systems (like the OS).
Public means may be used anywhere by any client of the class.
No matter how or where or IF you declare a method, at all.. If it exists.. calling it is as simple as
[myInstance performSelector:NSSelectorFromString(#"yourSuperSecretMethod:")
withObject:myKillerObject];
If the method got compiled.. It will get called. There is no "hiding" it. Even if not declared, the runtime "gives up" this information to any interested party. #see class-dump, if interested in learning more.

Objective-C Category [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
What happens if two ObjC categories override the same method?
I have two Categories on NSString class as follows:
//first category
#import "NSString+MyCategory1.h"
#implementation NSString (MyCategory1)
-(void)myMethod{
NSLog(#"this is my method from category 1");
}
#end
//second category
#import "NSString+MyCategory2.h"
#implementation NSString (MyCategory2)
-(void)myMethod{
NSLog(#"this is my method from category 2");
}
#end
But the following main method is always calling myMethod from MyCategory1 even after import of the same has been commented out.
#import <Foundation/Foundation.h>
//#import "NSString+MyCategory1.h"
#import "NSString+MyCategory2.h"
int main(int argc, const char * argv[])
{
#autoreleasepool {
[[[NSString alloc]init] myMethod];
}
return 0;
}
Please anyone explain this behavior and how this behavior is useful in practice.
I think what this shows is that you should not have methods in categories that clash.
My (semi informed) guess is that which method gets called us down to how the app was compiled, so it's not something you can influence at runtime. And it's not really useful in practice, it's just... what happens.
As for why this happens, the header file doesn't say what to do when the method is called, only that an implementation for it exists. In your case, it does exist. It just happens not to be the one you want.

Extend iTunesApplication class with Categories

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];
}