In Delphi, is normal do this:
ob = TObject.create;
try
//code
finally
ob.free;
end;
I wonder if that is similar in Obj-c.
You could do it that way, but exceptions tend to have a high cost in Objective-C. There are some differences in their performance between the 32-bit and 64-bit ABIs, as well as the interaction between Objective-C exceptions and C++ exceptions.
An alternative is to create your objects such that they are autoreleased and only retain them before your method ends.
SomeClass *object = [[[SomeClass alloc] init] autorelease];
/* deadly code here */
return [object retain];
This way even if your code experiences an exception your object will be released the next time the autorelease pool is drained (usually at the end of the event loop), assuming that the exception is not fatal and causes your program to crash.
Apple has some documentation about Obj-C exceptions
and the release notes for Leopard towards the end discuss the changes in the 64-bit ABI.
No. Objective-C does support exceptions and you see them in Cocoa infrequently (NSError is the direction Apple is headed) but you definitely wouldn't use them every time you initialize or release an object.
I'm certainly no expert in Obj-C but the fact that it provides (what people have asked in Delphi) the compound try/catch/finally, gives you the choice to use that to program defensively like in Delphi:
#try {
// protected block
}
#catch (id theException) {
// do smthing with theException
}
#finally {
// clean up code
}
And I would argue that if programmers used the #finally more often, there would be less bugs in their developments.
good answers, however...
I stand to be corrected, but it is my understanding that #try {} #finally {} is different in concept and therefore application to #try {} #catch {} #finally {}, in that if you don't raise any exceptions there is minimal overhead, however when exceptions are raised (which should be by definition, the "exception rather than the rule"), they serve to protect the resource being wrapped, leaving a #catch handler further up the food chain to deal with logic side of dealing with the exception.
as an example, here is a construct i often use when i have to return an autoreleased value that would autorealease a lot of extraneous data into the callers pool, if it were not for the #try/#finally/drain/autorelease construct you see here.
+(NSArray *) arrayOfUrlPrefixAssociatedUrlArraysFromUnsortedArrayOfUrlStrings:(NSArray *)urlStrings {
NSArray *arrayResult = nil;
NSAutoreleasePool *wader = [[NSAutoreleasePool alloc] init];
#try {
NSMutableDictionary *result = [NSMutableDictionary dictionary];
for (NSString *urlString in urlStrings) {
BOOL addedToPrior = NO;
for (NSString *prefix in result.allKeys) {
if ([urlString hasPrefix:prefix]) {
[(NSMutableArray *) [result objectForKey:prefix] addObject:urlString];
addedToPrior = YES;
break;
}
}
if (!addedToPrior) {
[result setObject:[NSMutableArray arrayWithObject:urlString] forKey:[self urlPrefixFromUrlString:urlString]];
}
}
arrayResult = [[NSArray alloc] initWithArray:[result allValues]];
}
#finally {
[wader drain];
}
return (arrayResult?[arrayResult autorelease]:nil);
}
Related
I have a property declared on an object in Objective-C that's called from multiple threads:
#property (atomic, strong) NSNumber *validLock;
In my setter, I do the following:
#synchronized(self.validLock) {
self.validLock = #YES;
}
In my getter, I do the following:
#synchronized(self.validLock) {
if (self.validLock.boolValue) {
...
}
}
Despite all these precautions, the thread sanitizer in Xcode still breaks on the #synchronized getter line with a comment "Data Race detected."
I even ditched the '#synchronized' idea and went all-in with NSLock to no avail.
This is becoming laughable, as this also gets tagged on [myLock lock] by the Xcode thread sanitizer:
NSLock *myLock = [[NSLock alloc] init];
...
[myLock lock];
self.validLock = #NO;
[myLock unlock];
What am I doing wrong?
This isn't particularly meaningful:
#synchronized(self.validLock) {
self.validLock = #YES;
}
I think you're expecting this to synchronize on "the validLock property of self" but that's not what the parameter means. You're synchronizing on the NSNumber that is currently pointed to by validLock (an NSNumber that you then replace). Since this is not the same object that you synchronize against elsewhere, this doesn't do much.
Similarly, if this code is all in the same context (which is what your example suggests), it doesn't do anything either:
NSLock *myLock = [[NSLock alloc] init];
...
[myLock lock];
self.validLock = #NO;
[myLock unlock];
Each thread would have its own lock.
First, you really want to avoid both NSLock and #synchronized. They've been superseded by GCD for many years now. See the Concurrency Programming Guide for full details.
If you really want to use #synchronized (realizing that it is pretty inflexible and quite slow), then typically you call it on self.
#synchronized(self) {
self.validLock = #YES;
}
But in any case, it has to be on the same actual object (not just the same name of an object).
If you're going to use NSLock, you need to make sure everyone is sharing the same actual lock, so for a single instance it needs to be a property. For multiple instances it needs to be a global or at least a class property.
I am coding Objective-C using the Cocos2D framework, and I have a singleton used for multiple purposes. One new purposes is to get and set character's "states" which are strings. I've recently made an NSDictionary for this purpose, but I have issues with the program freezing up when a method inside the singleton is called.
Here's the singleton code. I'm just leaving in the character state stuff:
.h
#interface ExGlobal : NSObject {
NSArray *charStates_keys;
NSArray *charStates_objects;
NSMutableDictionary *charStates;
}
#property(nonatomic, retain) NSMutableDictionary *charStates;
+(ExGlobal*)sharedSingleton;
- (NSString *)charState:(NSString *)charName;
- (void)set_charState:(NSString *)value forCharName:(NSString *)charName;
#end
.m
#import "ExGlobal.h"
#implementation ExGlobal
#synthesize charStates;
static ExGlobal* _sharedSingleton = nil;
+(ExGlobal*)sharedSingleton {
#synchronized([ExGlobal class]) {
if (!_sharedSingleton) {
[[self alloc] init];
}
return _sharedSingleton;
}
return nil;
}
+(id)alloc {
#synchronized([ExGlobal class]) {
NSAssert(_sharedSingleton == nil, #"Attempted to allocate a second instance of a singleton.");
_sharedSingleton = [super alloc];
return _sharedSingleton;
}
return nil;
}
-(id)init {
self = [super init];
if (self != nil) {
// initialize stuff here
exitName = #"ruinsSkyMid";
sceneChangeKind = #"reborn";
charStates = [[NSMutableDictionary alloc] init];
charStates_keys = [NSArray arrayWithObjects:#"Feathers", #"Hummus", nil];
charStates_objects = [NSArray arrayWithObjects:#"at wall", #"with Feathers", nil];
charStates = [NSMutableDictionary dictionaryWithObjects:charStates_objects forKeys:charStates_keys];
}
return self;
}
- (NSString *)charState:(NSString *)charName{
NSString *value = [charStates objectForKey:charName];
return value;
}
- (void)set_charState:(NSString *)charState forCharName:(NSString *)charName{
[charStates setObject:charState forKey:charName];
}
- (void)dealloc {
//I know it doesn't get called, but just in case
[charStates release];
[super dealloc];
}
#end
It's unclear to me what exactly the issue is when it freezes. When this happens, all I get in the console is:
Program received signal: “EXC_BAD_ACCESS”.
warning: Unable to read symbols for /Developer/Platforms/iPhoneOS.platform/DeviceSupport/4.3.5 (8L1)/Symbols/Developer/usr/lib/libXcodeDebuggerSupport.dylib (file not found).
Previous frame inner to this frame (gdb could not unwind past this frame)
Previous frame inner to this frame (gdb could not unwind past this frame)
Which I'm sure doesn't help finding the issue. I found if I redefine charStates_keys, charStates_objects and charStates inside both the charState and set_charState methods, it seems to work without freezing, except set_charState does not change the state.
It isn't freezing, it is crashing. Hence the EXC_BAD_ACCESS. It looks like your Xcode installation is borked, too, as the two messages following should not happen.
Note that methods should not have _s in the name; not a cause of the problem, but a comment on following convention.
You aren't retaining charStates and that is likely the cause of the crash.
Not an answer as such but I didn't have enough space in the comments field above to post this, but it might be useful.
As bbum already said, your lack of retaining charStates is likely the problem.
If you are confused about when to retain and not retain objects there's a really good book called "Learn Objective-C on the Mac" and I know it's a Mac book but most of it applies to iPhone too. On page 171 of chapter 9 (Memory Management) it talks about the "Memory Management Rules" and how if you are confused about when to retain or not then you don't understand the simple rules of Objective C memory management.
Essentially if you create an object using new, alloc or copy, then the retain count is automatically set to 1 so the object is retained and does not require you to retain it and will require a subsequent release to deallocate.
If you create the object any other way then the object will be an autoreleased object.
Obviously these rules only apply within the standard iOS libraries and can't necessarily be applied to third party libraries.
I recommend anyone who doesn't fully understand memory management in Objective C read this book. I found highly enlightening even for my iPhone work.
Hope that helps/.
Generally speaking goto is bad (we all know why) What would be a better way to implement a simple cleanup on an error (as in the example below) without having to duplicate the code. To my mind the code below is fine, I was just curious what others would do:
int main (int argc, const char * argv[]) {
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init]
int returnCode = 0;
// ... Other code
// WRITE: To file
if([dataStore writeToFile:savePathData atomically:YES] == NO) {
NSLog(#"writeToFile ... Error");
returnCode = 1;
goto cleanUpCode;
}
// ... Other code
// Clean up
cleanUpCode:
[archiver release];
[newPlanet release];
[pool drain];
return(returnCode);
}
EDIT_001:
In general terms I agree that #try, #catch, #finally are more than certainly the way to go but I do have two small concerns.
(1) The three #try, #catch, #finally blocks must all be together, you don't have the flexibility to place code between the #catch and #finally that you might want to bypass.
(2) Apple's documentation for Obj-C 2.0 states the following: "Important: Exceptions are resource-intensive in Objective-C. You should not use exceptions for general flow-control, or simply to signify errors (such as a file not being accessible)".
much appcreciated
gary
This is a common idiom in C code, and I don't think there is anything wrong with it in the absence of a language with more comprehensive creation/destruction semantics.
Goto is considered harmful in the general sense; it can make program execution difficult to follow. Here, it's very limited in scope, and the flow is unidirectional. It's also helpful in the sense that it allows you to localize your cleanup code, which is a good thing.
Well, first of all I would try to refactor it into some more methods, maybe then the code would not be so illegible?
Also, you can always use autoreleased objects and so you only need the [pool drain] at the end. And this can probably be done using #try/#finally, so that you can just return 1 instead of returnCode = 1.
E.g. take a look at the Exception Handling and Memory Management document (I know your question is not about exceptions, but this is basically all the same) - they recommend something like this:
- (void)doSomething {
NSMutableArray *anArray = nil;
array = [[NSMutableArray alloc] initWithCapacity:0];
#try {
[self doSomethingElse:anArray];
}
#finally {
[anArray release];
}
}
Personally, this is what I would do.
There are many ways to do this. Here's a couple:
Write a procedure corresponding to your main code, e.g. RunApplication. Put the call to it in the "else" branch.
Put it in a try/catch, do the error handling in the "catch" section, normal processing otherwise.
Code
e.g. try {
.. check for error (any function/procedure that checks for an error can throw an exception
.. do normal processing (still a good idea to factor this out into a procedure, for clarity
}
catch {
.. handle errors
}
finally
{
.. do cleanup
}
Anytime you think you need a goto, for an error case, you will probably find that a try/catch and exception works better.
In languages without try/catch, just use refactoring.
As you are describing something that looks like a small command line program I wouldn't worry about it. Because when your program ends all memory allocated by the program will be returned to the system (it will cease to exist). But, if you had a bigger program that allocates a lot and runs for a while you might look into cleaning more correctly as it can help tracking down memory leaks which could affect a program that runs a longer time. In that case I'd also suggest using some macros.
#define THROW( _name ) goto label_ ## _name
#define CATCH( _name ) label_ ## _name:
:
:
if([dataStore writeToFile:savePathData atomically:YES] == NO) {
NSLog(#"writeToFile ... Error");
returnCode = 1;
THROW( cleanUpCode );
}
:
:
CATCH( cleanUpCode )
[archiver release];
[newPlanet release];
[pool drain];
Does #synchronized not use "lock" and "unlock" to achieve mutual exclusion? How does it do lock/unlock then?
The output of the following program is only "Hello World".
#interface MyLock: NSLock<NSLocking>
#end
#implementation MyLock
- (id)init {
return [super init];
}
- (void)lock {
NSLog(#"before lock");
[super lock];
NSLog(#"after lock");
}
- (void)unlock {
NSLog(#"before unlock");
[super unlock];
NSLog(#"after unlock");
}
#end
int main (int argc, const char * argv[]) {
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
MyLock *lock = [[MyLock new] autorelease];
#synchronized(lock) {
NSLog(#"Hello World");
}
[pool drain];
}
The Objective-C language level synchronization uses the mutex, just like NSLock does. Semantically there are some small technical differences, but it is basically correct to think of them as two separate interfaces implemented on top of a common (more primitive) entity.
In particular with a NSLock you have an explicit lock whereas with #synchronized you have an implicit lock associated with the object you are using to synchronize. The benefit of the language level locking is the compiler understands it so it can deal with scoping issues, but mechanically they behave basically the same.
You can think of #synchronized as a compiler rewrite:
- (NSString *)myString {
#synchronized(self) {
return [[myString retain] autorelease];
}
}
is transformed into:
- (NSString *)myString {
NSString *retval = nil;
pthread_mutex_t *self_mutex = LOOK_UP_MUTEX(self);
pthread_mutex_lock(self_mutex);
retval = [[myString retain] autorelease];
pthread_mutex_unlock(self_mutex);
return retval;
}
That is not exactly correct because the actual transform is more complex and uses recursive locks, but it should get the point across.
In Objective-C, a #synchronized block handles locking and unlocking (as well as possible exceptions) automatically for you. The runtime dynamically essentially generates an NSRecursiveLock that is associated with the object you're synchronizing on. This Apple documentation explains it in more detail. This is why you're not seeing the log messages from your NSLock subclass — the object you synchronize on can be anything, not just an NSLock.
Basically, #synchronized (...) is a convenience construct that streamlines your code. Like most simplifying abstractions, it has associated overhead (think of it as a hidden cost), and it's good to be aware of that, but raw performance is probably not the supreme goal when using such constructs anyway.
Actually
{
#synchronized(self) {
return [[myString retain] autorelease];
}
}
transforms directly into:
// needs #import <objc/objc-sync.h>
{
objc_sync_enter(self)
id retVal = [[myString retain] autorelease];
objc_sync_exit(self);
return retVal;
}
This API available since iOS 2.0 and imported using...
#import <objc/objc-sync.h>
Apple's implementation of #synchronized is open source and it can be found here. Mike ash wrote two really interesting post about this subject:
Locks, Thread Safety, and Swift
Let's Build #synchronized
In a nutshell it has a table that maps object pointers (using their memory addresses as keys) to pthread_mutex_t locks, which are locked and unlocked as needed.
It just associates a semaphore with every object, and uses that.
Consider the following Cocoa/Obj-C code snippets:
MyClass *obj;
#try {
[obj doSomething];
}
#catch (NSException * e) {
NSLog(#"Exception occurred: %#", [e description]);
}
#finally {
[obj cleanUp];
}
and
MyClass *obj;
#try {
[obj doSomething];
}
#catch (NSException * e) {
NSLog(#"Exception occurred: %#", [e description]);
}
[obj cleanUp];
In what circumstances will the first snippet result in [obj cleanUp] being called, while the second won't result in [obj cleanUp] being called? In other words, in what circumstances is #finally non-redundant when using Cocoa Exception Handling?
In those scenarios there is no difference because the exception is swallowed. Here are two scenarios where there is a difference:
[obj cleanUp] is called:
MyClass *obj;
#try {
[obj doSomething];
}
#catch (NSException * e) {
#throw;
}
#finally {
[obj cleanUp]; // called when exception is caught
}
[obj cleanUp] is not called:
MyClass *obj;
#try {
[obj doSomething];
}
#catch (NSException * e) {
#throw;
}
[obj cleanUp]; // not called when exception is caught
It's also worth noting that code in #finally blocks will run when control exits the #try block for any reason, even via return or goto. For example:
#try {
doStuff();
if(bail){
return;
}
doMoreStuff();
}
#finally {
[obj cleanUp];
}
[obj announceSuccess];
[obj cleanUp] will execute even if bail is true, but [obj announceSuccess] will not.
In that case, where you’re squashing the exception, none. #finally is used to clean up when you either don’t catch the exception, or rethrow it, in either case leaving final exception response to calling code. Since exceptions in Cocoa are only supposed to be used for programming errors and thus occur rarely, this is an entirely reasonably thing to do.
It’s also worth pointing out one case where you don’t need to use #finally, which is when you set up your own autorelease pool. When the “parent” autorelease pool is destroyed, any inner ones that haven’t been cleaned up yet will also be. If you do try to clean it up yourself, you need to promote the exception itself out of your autorelease pool.
When:
You are not catching the type of exception that occured
You caught the exception, but the code in the catch block also throws an exception.
A lower level question, why are you doing this?
The try/catch/finally approach is widely used in Java but hardly ever used in Objective-C, and is not a preferred approach - you simply do not need it as libraries will not throw exceptions the way Java library calls would, and if you are writing your own libraries you should not expect callers will naturally think to look for exceptions to catch.
The convention most widely used and understood is that of a delegate that has an error method callback, or perhaps notifications for more general failures that you need to pass up through multiple levels of code. That approach might be more widely used in the Java world if there were a simple notification system the way Cocoa has it set up.
The delegate approach has the same documenting property as declaring an exception in Java does, they are just different approaches but it's generally better to use an approach more suited to the language at hand unless there's a very compelling reason to do otherwise.