I'm learning objc and Xcode from a handy free ebook called How To Become and Xcoder, which is quite handy. Except it was written in 2007 with Xcode 3 and its samples are all from that version unfortunately I have OSX Lion and thus Xcode 4. So to the grit of my question. They provide a sample block of code as seen here:
//start
#import <Foundation/Foundation.h
int main (int argc, const char * argv[])
{
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
NSLog(#"Hello, World!");
[pool drain];
return 0;
}
//end
So my problems are that I get over 20 errors and Xcode doesn't recognize the NSAutoreleasePool or NSLog commands.
Does anybody know why this won't work? I already added the Foundation framework.
The I've already realized that the printf command works better than the NSLog command (which to my knowledge is more so used for error reporting) so yeah any help would be nice.
If NSLog isn't being recognised, this isn't a problem to do with Xcode 3 versus Xcode 4. Your code isn't including the most basic Objective-C runtime code. I would assume that it's being compiled as C not Objective-C.
You say that you had to add the Foundation framework - this indicates that you didn't start your project using an Objective-C-based template. When you select New Project..., which template did you pick? Any of the iOS application templates should work, and most of the Mac OS X application templates should work. If you chose to build a command line tool, you should pick Foundation as the type.
Edit: Also, I should add that the syntax for autorelease pools has changed in the latest version of Xcode, as ARC is used by default. You can either switch ARC off, or read up on it to see what the differences are. Chances are you'll find it easier with ARC as there is much less memory management for you to worry about, but you will have to bear it in mind if you are following a book that doesn't account for it.
The Foundation is located on the screen where you need to give name to your project. As the default value it is set to C, in your case you need to click on the drop down menu and choose Foundation instead.
Good luck.
Related
Swift 2 have API availability checking.
The compiler will give you an error when using an API too new for your
minimum target OS
Why can't the objective-c compiler do the equivalent?
I googled objective c API availability checking and only swift 2 results came out so I assume the compiler for objective c can't do that.
Xcode 9.0 brings the runtime availability checking syntax from Swift to Objective-C:
if (#available(macOS 10.9, *))
{
// call 10.9+ API
}
else
{
// fallback code
}
this comes complete with warnings for calling APIs that are newer than your deployment target (if those calls are not wrapped in checks).
finally ;)
The warning (Swift makes it an error) just hadn't been implemented in the Clang compiler for years, but it's not an inherent Objective-C limitation (although due to its dynamic nature, you won't be able to catch all cases), nor Swift terminology.
The Apple macros (e.g., NS_CLASS_AVAILABLE) and source attributes (__attribute__((visibility(...))), __attribute__((availability(...)))) to annotate headers with availability information have been there for years, and they are widely-used in Apple's SDKs. The macros are defined in Foundation's NSObjCRuntime.h, and the Availability.h/AvailabilityMacros.h system headers, and the compiler can (and does) read them.
In early 2015, the -Wpartial-availability warning has been added to Clang's master branch, but this commit/warning hadn't made its way into Apple's version of Clang until (including) Xcode 7.2. You will get an unknown warning option log when adding the warning flag to a project in Xcode 7.2, but the flag is available in Xcode 7.3. There's currently no predefined setting for it, but you can add the flag to Other Warning Flags under Build Settings.
There are other tools that use LLVM libraries to detect partially available APIs, e.g., Deploymate. For my diploma thesis, I developed a tool that integrates directly into Xcode and is based on a modification to the Clang compiler. The code is still online, but I haven't kept up with the general Clang development so it won't be of much use, except for learning purposes. However, the "official" code (linked above) is much cleaner and better.
Edit: Starting with Xcode 9, availability checking will work for Objective-C (and C), too. Instead of using the above-mentioned warning flag, which does not support raising the deployment target temporarily/locally and therefore causes plenty of false positives, there's -Wunguarded-availability, and if (#available(iOS 11, *)) {...} to check and raise the deployment target for the following block of code. It is off by default, but -Wunguarded-availability-new will be on by default, and starts checking anything beyond iOS/tvOS 11, watchOS 4, and High Sierra. More details on that can be found in the Xcode 9 beta release notes, which currently requires signing in with a developer account.
Objective C does not have availability checking as part of the language, as the same result is available via Objective C preprocessor.
That is the "traditional" way of doing that in C derived languages.
Want to know if compiled in debug mode?
#ifdef DEBUG
// code which will be inserted only if compiled in debug mode
#endif
Want to check at compile time for a minimum version?
Use the Availability.h header in iOS, and similar headers for Mac OS X.
This file reside in the /usr/include directory.
just test __IPHONE_OS_VERSION_MAX_ALLOWED with the preprocessor, e.g.:
#if __IPHONE_OS_VERSION_MAX_ALLOWED >= 80000
if ([application respondsToSelector:#selector(registerUserNotificationSettings:)]) {
[[UIApplication sharedApplication] registerUserNotificationSettings:[UIUserNotificationSettings settingsForTypes:(UIUserNotificationTypeBadge|UIUserNotificationTypeSound|UIUserNotificationTypeAlert) categories:nil]];
}else{
[[UIApplication sharedApplication] registerForRemoteNotificationTypes: (UIUserNotificationTypeBadge|UIUserNotificationTypeSound|UIUserNotificationTypeAlert)];
}
#else
[[UIApplication sharedApplication] registerUserNotificationSettings: (UIUserNotificationTypeBadge|UIUserNotificationTypeSound|UIUserNotificationTypeAlert)];
#endif
As Swift does not have a preprocessor, they had to invent a way of doing these kind of checks within the language itself.
If you want to check availability of a method at runtime, please notice that the appropriate way is by using the method respondsToSelector:, or instancesRespondToSelector: (the latter at class level).
You will normally want to combine both approaches, compile time conditional compilation and runtime check.
Objective C method presence verification, e.g. at class level:
if ([UIImagePickerController instancesRespondToSelector:
#selector (availableCaptureModesForCameraDevice:)]) {
// Method is available for use.
// Your code can check if video capture is available and,
// if it is, offer that option.
} else {
// Method is not available.
// Alternate code to use only still image capture.
}
If you want to test if a C function exists at runtime, it is even simpler: if it exists, the function itself it is not null.
You can't use the same identical approach in both languages.
It does these days. Furthermore, with Xcode 11 (including the current Xcode 11.3.1), you can even get it from the snippets. Press the + button towards the top right of Xcode (as shown in the image below).
Then in the search box, type "API". All 3 versions of the snippet for API Availability Check will appear -- Objective C, C and Swift.
Of course, you will get errors in Objective-C code. But you won't find results in google for Objective-C, if you use a term defined for Swift as you will not find kisuaheli website in google if you search for a german word. ;-)
You will get an error linking Objective-C code against a too old SDK. This is simply because the used method or class or $whatever is not defined in the header for that SDK. Again, of course.
This is typical Swift marketing of Apple: Because of the incapability of Swift they have to extend the language to get something, which is quite easy in Objective-C. Instead of clarifying that this is the result of the poorness of Swift, they tell you that this is a great feature of Swift. It is like cutting your fingers and then saying: "We have the great plaster feature!!!!!!!!" And you have to wait only some days and one comes around on SO with the Q: "Why does Objective-C does not have the great plaster feature???????" The simple answer: It does not cut your fingers.
The problem is not to generate the errors. The problem is to have one source code for all versions, so you can simply change the SDK version and get new code (or errors). You need that for easier maintenance.
In Objective-C you simply can use the answer found here:
Conditionally Hide Code from the Compiler or you can do that at runtime as mentioned in the comments to the Q. (But this is a different solution of the problem by nature, because it a dynamic approach instead of a static one as you have to do in Swift.)
The reason for having a language feature in Swift is that Swift has no preprocessor, so the Objective-C solution would not work in Swift. Therefore conditional code would be impossible in Swift and they had to add the plaster, eh, language feature.
Is it at all possible to have Xcode create a .playground file for Objective-C instead of Swift? Are there any available Xcode plugins that allow that?
You can quickly test code snippets using a test case in a new project. Just create a new project and go to the Navigator in the left pane and hit the Test Navigator button. Then follow this guide
The setup code will look a little different than a swift playground, but it still allows you to prototype and play around.
There is a very good library developed by Krzysztof Zabłocki in Github entitled KZPlayground that support both code in Playgrounds for Objective-C and Swift and a lot of cool features.
I hope this can help you.
If the only purpose is to test out Objective-C snippets, i would really recommend you an OS X command line Tool project.
There are enough moving parts in a playground, and all of those would have to be reimplemented for Objective-C. Reliable playgrounds also depend on definite initialization which Objective-C does not have.
For instance consider:
var d: NSData // this is not initialized, so I can't use it
vs.
NSData *d; // this is also not initialized, but now I can use it
If I am the person storing the description of your NSData for the sidebar, now I know that I am not supposed to do
describe(d)
in the Swift case, but for the Objective-C case, I don't have equal knowledge and I run the risk of saying
[d description]; // even though d is a random pointer now.. oops, I just crashed!
In short, I don't think any such thing exists, and making one work would also involve some trickery
Trying to automatically view a computer in Apple Remote Desktop via Scripting Bridge in Objective-C with this:
#try {
SBApplication *RD = [SBApplication applicationWithBundleIdentifier:#"com.apple.RemoteDesktop"];
// (code to check for ARD running and installed omitted here)
[RD activate]; // works just fine
RemoteDesktopComputer *computer = [[[RD classForScriptingClass:#"computer"] alloc] initWithProperties:
[NSDictionary dictionaryWithObjectsAndKeys:
ipAddress,#"InternetAddress", // looked up from header
nil
]
];
// attempt to add it to a container first:
[(SBElementArray*)[(RemoteDesktopApplication*)RD computers] addObject:computer];
// this is what raises the exception:
[computer observeZooming:Nil];
}
#catch (NSException *e) {
NSLog(#"Exception: %#", [e description]);
}
Running this yields the following exception in the log:
Exception: *** -[SBProxyByClass observeZooming:]: object has not been added to a container yet; selector not recognized [self = 0x6050004819b3]
I've done as much research as there is available on this subject and have learned that SB isn't the easiest to deal with because of how it's wired under the hood, but any experts or veterans of native Scripting Bridge (no third party frameworks or languages other than obj-c, please) is much appreciated.
All prerequisites like linking to the ScriptingBridge.framework and importing Remote Desktop.h are performed - the typecasts are to avoid what appear to be unavoidable link-time errors when building...
Edit 1: Reading the documentation on SBObject (parent of RemoteDesktopComputer) says that it's a reference rather than an actual instance, which you can fetch by calling SBObject's get method (returns id). So I tried running this as well but unfortunately received the same results:
[[computer get] observeZooming:Nil];
Here's the documentation on SBObject: https://developer.apple.com/library/mac/documentation/cocoa/Reference/SBObject_Class/SBObject/SBObject.html#//apple_ref/occ/instm/SBObject/get
Still trying...
(FWIW, I already had the following How To written up, so I'm leaving it here for future reference.)
How to use AppleScript-ObjC in place of Scripting Bridge
Scripting Bridge is, at best, an 80/20/80 "solution" (i.e. 80% of the time it works, 20% of the time it fails, and 80% of the time you've no idea why). There's little point trying to argue with SB when it breaks on stuff that works perfectly well in AppleScript - the Apple engineers responsible designed it that way on purpose and simply refuse to accept they broke spec [1] and screwed up. As a result, the AppleScript language, for all its other deficiencies, remains the only supported solution that is guaranteed to speak Apple events correctly [2].
Fortunately, since OS X 10.6 there has been another option available: use ObjC for all your general programming stuff, and only call into AppleScript via the AppleScript-ObjC bridge for the IPC stuff.
From the POV of your ObjC code, your AppleScript-based ASOC 'classes' are more or less indistinguishable from regular ObjC classes. It requires a bit of fiddling to set up, and you'll pay a bit of a toll when crossing the bridge, but given the crippled, unreliable nature of the alternatives, it's the least horrid of the supported options for anything non-trivial.
Assuming you've already got an existing ObjC-based project, here's how to add an ASOC-based class to it:
In Targets > APPNAME > Build Phases > Link Binary With Libraries, add AppleScriptObjC.framework.
In Supporting Files > main.m, add the import and load lines as shown:
#import <Cocoa/Cocoa.h>
#import <AppleScriptObjC/AppleScriptObjC.h>
int main(int argc, const char * argv[]) {
[[NSBundle mainBundle] loadAppleScriptObjectiveCScripts];
return NSApplicationMain(argc, argv);
}
To define an ASOC-based class named MyStuff that's callable from ObjC, create a MyStuff.h interface file that declares its public methods:
// MyStuff.h
#import <Cocoa/Cocoa.h>
#interface MyStuff : NSObject
// (note: C primitives are only automatically bridged when calling from AS into ObjC;
// AS-based methods with boolean/integer/real parameters or results use NSNumber*)
-(NSNumber *)square:(NSNumber *)aNumber;
#end
along with a MyStuff.applescript file containing its implementation:
-- MyStuff.applescript
script MyStuff
property parent : class "NSObject"
on square_(aNumber)
return aNumber ^ 2
end square_
end script
Because the MyStuff class doesn't have an ObjC implementation, the linker can't link your ObjC code to it at build-time. Instead, use NSClassFromString() to look up the class object at run-time:
#import "MyClass.h"
...
MyStuff *stuff = [[NSClassFromString(#"MyStuff") alloc] init];
Otherwise it's pretty much indistinguishable from a native ObjC class in normal use:
NSNumber *result = [stuff square: #3];
NSLog(#"Result: %#", result);
HTH
--
[1] Apple management broke up the original AppleScript team shortly after its initial release, causing its designers to quit in response, so a lot of knowledge of precisely how this stuff should work was lost. In particular, a full, formal specification was never produced for application developers to follow when designing their scripting support, so all they could do was use personal judgement and best guesses, then test against AppleScript to check it worked as hoped. Thus, AppleScript's own Apple event bridge is the de facto specification that every single scriptable app has been implemented against in the last twenty years, so the only way that other AE bridges can ever work correctly is if they mimic AS's own bridge down to every last query and quirk - a lesson, unfortunately, that the current AS team have repeatedly failed to understand [2].
[2] JavaScript for Automation's Apple event supported is equally crappy and busted, incidentally.
Scripting Bridge is a defective, obfuscated mess, so when an application command fails to work you've no idea if the problem is SB being defective or the application itself being buggy or simply requiring you to phrase it in a different way.
Therefore, the first step is to write a test script in AS to see it works there. If it does, it's SB that's crap; if not, try fiddling with your AS code (e.g. try phrasing the reference for the at parameter in different ways, or omitting it entirely) till it does.
You should also ask on Apple's AppleScript Users and ARD mailing lists and anywhere else that ARD scripters are likely to hang out, as most apps' scripting documentation is grossly inadequate, so a lot of knowledge of how to do things is word of mouth. (The guy you really want to talk to is John C Welch, aka #bynkii, as he's the guru of ARD scripting.)
I'm very new in the world of xcode and Objective- C- Programming. Right now I'm learning programming via "Objective C- Programming: The big Nerd Ranch Guide". Because of an older OSX-Version, I was just able to install xcode 3.2.6. But the book uses the newest xcode version.
while going through the chapters, I faced a problem:
#import <Foundation/Foundation.h>
int main (int argc, const char * argv[])
{
#autoreleasepool{
NSDate *now = [NSDate date];
NSLog(#"The date is %#", now);
}
return 0;
}
this code sample gives me following error:
"expected expression before #-token"
While searching for a solution in web, I found out that it's a new syntax to xcode 4... I didn't know that there are so major differences between 3.2.6 and the newest version. Now my question: Does that mean all the syntax in xcode 4 has changed to the previous versions and the book is senseless for me? Or is it just this statement? (If yes, how to write in older versions? I even don't know what that statement is good for since I'm a bloody beginner)
You're confusing Xcode (the IDE), with the SDK. The #autorelease pool annotation was added in the iOS 5 SDK, which Xcode 4 happens to give you. If you want this to run in Xcode 3.x you need to make sure you are running it with the iOS 5 SDK.
In a word, YES.
Apple, since they pretty much own the entire stack, is free to change the language at whim, and 3.0 to 4.0 have some changes. I really would not waste my time trying to write IOS programs in 3 at this point personally.
The API's for the classes have changed with iOS as well between 3 and 4 and 4 and 5.
I would really suggest, upgrading your Mac to something that will support at least XCODE 4 at this point.
Replace #autoreleasepool {} with this code:
NSAutoreleasePool *pool = [NSAutoreleasePool new];
NSDate *now = [NSDate date];
NSLog(#"The date is %#", now);
[pool release];
The message you get refers to a new feature of Objective-C that is known as ARC and is meant to simplify memory management. It is available on Apple ObjC compilers starting with Xcode4.
You can still use the book, but you should remove all ARC-related statements (this is not only #autoreleasepool), and in practice it will not be easy because you will also need to add memory management.
I'm trying to compile the following Objective-C program on Ubuntu Hardy, but for some reasons, I'm getting warnings.
#import <Foundation/Foundation.h>
int main (int argc, char *argv[])
{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
NSLog (#"Hello");
[pool drain];
return 0;
}
Output of the compiler:
$ gcc `gnustep-config --objc-flags` -lgnustep-base objc.m
This is gnustep-make 2.0.2. Type 'make print-gnustep-make-help' for help.
Making all for tool LogTest...
Compiling file objc.m ...
objc.m: In function ‘main’:
objc.m:6: warning: ‘NSAutoreleasePool’ may not respond to ‘-drain’
objc.m:6: warning: (Messages without a matching method signature
objc.m:6: warning: will be assumed to return ‘id’ and accept
objc.m:6: warning: ‘...’ as arguments.)
Linking tool LogTest ...
Here's the result of the execution:
$ ./a.out
2009-06-28 21:38:00.063 a.out[13341] Hello
Aborted
I've done:
apt-get install build-essential gnustep gobjc gnustep-make libgnustep-base-dev
How do I fix this problem?
First, the simple answer: use -release instead. I believe -drain was added in 10.4 as an alias for -release, and in 10.5 it gained GC-specific behavior of its own. This allows code to use it in 10.5 and still work under 10.4. GNUstep probably doesn't yet have the new functionality.
Obviously you're trying out some boilerplate Objective-C code on Ubuntu, but it causes me to wonder what you're hoping to accomplish in the long term. Don't let me deter you if it's just out of curiosity or for the challenge of it. However, if you're planning to use GNUstep to develop Objective-C for serious programming, I would advise against it, for several reasons.
Objective-C is an interesting programming language with a number of powerful features, but not significantly more so (by itself) than other object-oriented languages. Objective-C really becomes compelling when you pair it with the cool features in Cocoa and other related frameworks. Apple (primarily) drives those frameworks, and only for Mac/iPhone.
Apple generally has the best tools and user experience for Objective-C development. They're also investing heavily in development of LLVM and Clang as a replacement for gcc. This will (an already does) make possible some very cool things that gcc wasn't designed for.
GNUstep is an admirable project, but since it depends on volunteers and reverse-engineering new features added by Apple, it always lags behind the state-of-the-art. The new shiny Objective-C features will always start with Apple and (usually) eventually trickle down.
Building cross-platform apps could be done in Objective-C, but other languages are much better suited for the task. (I'm not so much of a fanboy as to suggest that Objective-C is the best solution for every problem. Use the best tool you have at hand.)
I'm not saying using languages on something other than their "native platform" is bad. I'm just suggesting that if that's what you're going to do, you should be aware of the potential problems and be sure you're convinced that the pros outweigh the cons.
Sounds like the class library is out of date in GNUStep, at least in the version you're using -- [NSAutoreleasePool drain] was added in OS X 10.4 IIRC. I don't know anything about GNUStep though, so I don't know if newer libraries are available.
You can work around the problem by replacing 'drain' with 'release'. They do basically the same thing; the 'drain' method was added for use in a garbage-collected app, because 'release' becomes a no-op in that environment.
In my app main loop using GNUStep:
int main(int argc, const char *argv[])
{
NSAutoreleasePool *pool;
AppController *delegate;
pool = [[NSAutoreleasePool alloc] init];
// ...
[pool release];
return NSApplicationMain (argc, argv);
}