Objective c dictionary enumeration with blocks does not work on gcc with gnustep - nsdictionary

I am just learning obj c. I am using GNUStep downloaded from gnustep.org/experience/Windows.html (there are 3 installers - msys system, core, devel) some time back.
Running the below code:
#import <Foundation/Foundation.h>
int main (int argc, char *argv[]) {
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
NSDictionary *m_Dict =
[NSDictionary dictionaryWithObjectsAndKeys:
#"ABC", #"One",
#"DEF", #"Two",
#"GHI", #"Three",
nil ];
// Print all key-value pairs from the dictionary
[m_Dict enumerateKeysAndObjectsUsingBlock: ^(id key, id obj, BOOL *stop) {
NSLog(#"%# => %#", key, obj);
}];
[pool drain];
return 0;
}
is showing an error:
$ gcc -o c c.m -I /GNUstep/System/Library/Headers -L /GNUstep/System/Library/Li
``braries -lobjc -lgnustep-base -fconstant-string-class=NSConstantString
c.m: In function 'main':
c.m:16:44: error: expected expression before '^' token
c.m:18:1: warning: 'NSDictionary' may not respond to '-enumerateKeysAndObjectsUs
ingBlock:' [enabled by default]
c.m:18:1: warning: (Messages without a matching method signature [enabled by def
ault]
c.m:18:1: warning: will be assumed to return 'id' and accept [enabled by default
]
c.m:18:1: warning: '...' as arguments.) [enabled by default]c
Please suggest what I am doing wrong. searched here on Stackoverflow also but couldn't find much help.

Your compiler doesn't support blocks. You need to use a modern clang.
Really, if you're learning Objective-C for the purpose of writing code for the Mac or iPhone/iPad, your first step needs to be to purchase a Mac and install Xcode. If you learn using older compilers, you'll be missing out on language features and you'll need to relearn the patterns you use later.
Check Mountain Lion's requirements before purchasing a Mac. You can technically run the latest Xcode on Lion, but I don't think Apple will keep it compatible for long.
Alternately, if you're just trying to learn Objective-C, you'll need to figure out what subset of the language you can use. I suggest this isn't terribly useful outside of iOS/Mac development, though.

Related

ARC forbids autorelease?

New to ios and trying to return an NSString from an function. As I understand, I need to [NSString... alloc] init] in order to create the string for return. Also, since I called alloc, I guess I have to autorelease the object myself however I'm getting the message "ARC forbids explicit message send of 'autorelease'" so.. how do I tell ios when I'm done with that allocated NSString?
- (NSString *) generateUID
{
char foo[32];
// create buffer of all capital psuedo-random letters
for (int i = 0; i < sizeof(foo); i++)
foo[i] = (random() % 25) + 65; // 0-25 + CAPITAL_A
NSString *uid = [[NSString alloc] initWithBytes:foo length:sizeof(foo) encoding:NSASCIIStringEncoding];
NSLog (#"uid: %#", uid);
return (uid);
}
ARC = automatic reference counting = the compiler adds the necessary releases and autorelases based on its analysis of your code. You don't see this of course because it happens behind the scenes. As mentioned by sosbom in his comment, you really should read the applicable documentation on the Apple website.
You don't.
autorelease is just there for compatibilities sake, prior to iOS 5, you'd have to do:
Thing *myThing = [[Thing alloc] init]; // Retain count: 1
[myArray addObject:myThing]; // Retain count: 2
[myThing release]; // Retain count: 1
With the above code, the responsability of holding the object is given to the array, when the array gets deleted, it will release its objects.
Or in the case of autorelease.
- (MyThing*)myMethod
{
return [[[MyThing alloc] init] autorelease];
}
Then it would release the object once it gets to a NSAutoReleasePool and get removed once drained.
ARC takes care of that now, it pretty much inserts the missing pieces for you, so you don't have to worry about it, and the beauty of it, is that you get the advantages of reference counting (vs garbage collector), at the cost of an increased compile-time checking to do the ARC step, but your end users don't care about compile-time.
Add to that, that you now have strong and weak (vs their non-ARC siblings retain and assign, the later one still useful for non-retained things), and you get a nice programming experience without tracing the code with your eyes and counting the retain count on your left hand.
Short answer is you don't! ARC will handle the memory management for you.
When ARC is turned on, the compiler will insert the appropriate memory management statements such as retain and release messages.
It is best to use ARC as the compiler has a better idea of an object's life cycle and is less prone to human error.
One other important thing to note about ARC. ARC is not the same as traditional garbage collection. There is no separate process or thread running in the background, like java's GC, which deletes objects when there is no longer a reference to them. One could view ARC as compile time garbage collection :).
The only other thing to be aware of is reference cycles and bridging pointers/objects between Objective-C and Obj-C++/C. You might want to look-up http://en.wikipedia.org/wiki/Weak_reference
Hope this helps
In general, you should define a constructor method in your class and put the alloc logic in that method. Then, it is much harder to make a type casting error as the alloc/init approach always return (id) and it is not very type safe. This what built-in classes like NSString do, like [NSString stringWithString:#"foo"], for example. Here is a nice little block you can use to write code that works both with older non-arc compilation and with arc enabled.
+ (AVOfflineComposition*) aVOfflineComposition
{
AVOfflineComposition *obj = [[AVOfflineComposition alloc] init];
#if __has_feature(objc_arc)
return obj;
#else
return [obj autorelease];
#endif // objc_arc
}
You then declare the method and create an instance of the object like so:
AVOfflineComposition *obj = [AVOfflineComposition aVOfflineComposition];
Using the above approach is best, as it is type safe and the same code with with arc vs non-arc. The compiler will complain if you attempt to assign the returned object to a variable of another type.

CorePlot 1.0 + LLVM GCC 4.2 + ARC - How to?

I'm trying out CorePlot in a small personal project to draw some bar graphs. I started the project using Xcode 4.3.2 and ARC, thinking it'd make my life easier... The problem is, when using GCC 4.2 - the compiler doesn't recognise #autorelease. I got past that using:
int retVal = 0;
// #autoreleasepool {
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
retVal = UIApplicationMain(argc, argv, nil, NSStringFromClass([kerrAppDelegate class]));
[pool drain];
// }
return retVal;
However I get the error saying that NSAutoreleasePool isn't available in ARC... Does anyone have any recommendations?
This really has nothing to do with Core Plot.
Automatic reference counting is only supported when using the LLVM Compiler 3.0 or higher. LLVM GCC 4.2 doesn't support ARC, so you'll want to switch your project over to use the full LLVM Compiler.

Sending message to objectForKey to NSMutableArray instance, And it works!! Strange?

I have a very bad code written in my program, was just playing around as I am learning Objective C and iOS platform. What I did is,
I have created NSMutableArray like this,
placeInfo = [NSMutableArray array];
and than later in my code I am doing something like this, basically I am manipulating Google places api response(JSON).
NSDictionary *results = [responseString JSONValue];
placeInfo = [results objectForKey:#"result"];
self.phoneNumber = (NSString *)[placeInfo objectForKey:#"formatted_phone_number"]; // In this line compiler warns me that NSMutableArray might not response to this.
I checked documentation but I didn't find objectForKey in NSMutableArray.
So what could be the reason? Why my code isn't crashing? Why it is returning phone number by "formatted_phone_number" key?
EDIT
After first answer I have edited my code and added type casting like this, but it still works.
NSDictionary *results = [responseString JSONValue];
placeInfo = (NSMutableArray *)[results objectForKey:#"result"];
self.phoneNumber = (NSString *)[placeInfo objectForKey:#"formatted_phone_number"];
I’ve never used the Google Places API, but I’d guess [results objectForKey:#"result"] actually returns another dictionary, so the objectForKey: works.
Because objective-c just uses pointers to refer to objects, it’s never actually being converted to an NSMutableArray. Also, objective-c doesn't know at compile time if a method will exist, due to its dynamic nature (you can actually add methods and even whole classes at runtime).
Depending on the compiler settings, it may just show a warning that objectForKey: might not be found at runtime, and let it continue compiling anyway. It ends up working just fine if you actually passed it an NSDictionary.
Even when you put the (NSMutableArray *) cast in front of it, it won’t change anything. That simply casts the pointer type, and doesn’t actually change the object in any way.
It's doing this because [results objectForKey:#"result"] is returning you something that is not an NSMutableArray. That something that's being returned is likely another NSDictionary which, of course, does respond to objectForKey: To find out what you've got, set a breakpoint after result = [placeInfo objectForKey:#"result"] and inspect result. The debugger will tell you what kind of object you're dealing with. I'll bet you anything you like that it's an NSDictionary.
Objective C allows you to send any message (called a selector) to any object at any time; the runtime does not care whether a particular object implements a given selector. If the target object does not respond to a given selector it will ignore it. It will not crash. In this respect it's utterly unlike most other OOP languages, including C++ and Java, which will fail to compile if you try to call a method that a particular class doesn't implement. You can find out if an object responds to a given selector (which is analagous to using introspection to see if a given class implements a certain method) by saying [result respondsToSelector:#selector(objectForKey:)]. This difference between methods and messages is critically important to understanding Objective C. I'd recommend reading The Objective C Programming Language before doing anything else.
Also, Objective C's type system is less stringently enforced than those other languages. It's quite legal (although a very bad idea) to do what you have done here, which is to declare a pointer of type NSMutableArray and then assign it to (I'm guessing) an NSDictionary.

NSStringFromPoint disappears under Objective-C++

The function NSStringFromPoint disappears when I compile my code using objective-C++, but it's fine under objective-C.
How can I make objective-C++ see that function?
If I compile under Objective-C++ it says:
error: 'NSStringFromPoint' was not declared in this scope
error: 'NSStringFromRect' was not declared in this scope
error: 'NSEqualSizes' was not declared in this scope
Someone can correct me if I'm wrong, but if you're linking against the iPhone SDK, there is no NSPoint or NSStringFromPoint. UIKit uses the Core Graphics structs CGPoint, CGSize and CGRect. The equivalent function would be NSStringFromCGPoint.
The Simulator libraries do not quite match up with the iPhone libraries -- I'm fairly certain applications compiled for the simulator link against the Mac's own Foundation.framework. For example, I wasted a lot of time in the pre-2.0 days thinking that NSXMLDocument was available on iPhone because it compiled and ran in the simulator.
I compiled this simple application:
#include <Cocoa/Cocoa.h>
int main (void)
{
NSLog (#"%#", NSStringFromPoint(NSMakePoint(10, 10));
return 0;
}
Using this command line:
gcc -x objective-c++ test.mm -framework Cocoa -lstdc++
And I got this output (ignoring the error about no autorelease pool in place):
2010-05-12 12:41:33.946 a.out[290:10b] {10, 10}
Make sure you're including the right headers, at the very least, make sure you're importing <Foundation/Foundation.h>. An explicit #import <Foundation/Foundation.h> will do no harm if it has already been included.

Changing Backlight Level, iPhone

I searched around for a way to set the backlight level within an app on the iPhone. I found a solution here:
http://www.iphonedevsdk.com/forum/29097-post3.html
The problem I have is, when I add this to my app I get an error and a warning. My code is as follows:
#include "GraphicsServices.h"
- (void) viewWillAppear:(BOOL)animated
{
NSNumber *bl = (NSNumber*) CFPreferencesCopyAppValue(CFSTR("SBBacklightLevel" ), CFSTR("com.apple.springboard"));
previousBacklightLevel = [bl floatValue];
//Error here : incompatible types in assignment
[bl release];
GSEventSetBacklightLevel(0.5f);
// Warning here : implicit declaration of function 'GSEventSetBacklightLevel'
}
//...The rest of my app
- (void)applicationWillTerminate:(UIApplication *)TheNameOfMyAppIsHere
{
GSEventSetBacklightLevel(previousBacklightLevel);
}
I am unsure of what is causing this. I also don't really know what needs to be in my .h file here, but I have:
NSNumber *previousBacklightLevel;
EDIT// Changed
NSNumber *previousBacklightLevel
to
float previousBacklightLevel;
as suggested and this sorted the incompatible types in assignment error.
Now left with:
"_GSEventSetBacklightLevel", referenced from:
-[MyAppViewController viewWillAppear:] in MyAppViewController.o
-[MyAppViewController applicationWillTerminate] in MyAppViewController.o
symbol(s) not found
collect2: ld returned 1 exit status
Not sure how to fix this one either!
Any help would be appreciated,
// EDIT
All problems sorted. Thanks to all who helped me out. I really do appreciate it and can't wait till I can give a little back, by answering some questions.
Many thanks,
Stu
The reason you are getting a warning is because GSEventSetBacklightLevel() is a private API not declared in any of of the SDK headers. If you are planning to submit this to the app store your app will get rejected if you call it. If this is for a jailbroken device, you can just declare the function yourself.
void GSEventSetBacklightLevel(float level);
The reason you are getting the error is because you are trying to assign a float (which is a scalar) to an NSNumber *. You probably want to change previousBacklightLevel to be a float.
you can add the private framework by jus drag and drop to your xcode project from /Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS4.2.sdk/System/Library/PrivateFrameworks/GraphicsServices.framework and also import the #import "GraphicsServices.h" header in your .h file