A Class Property, Such as:
#interface TestModel
#property (nonatomic, copy) NSString *testStr;
#end
At main Thread:
for (model in modellist) {
if ((!model.testStr || ![model.testStr isKindOfClass:[NSString class]] || model.testStr.length == 0)) {
NSLog(#"empty str");
}
NSLog(#"not empty str");
}
At BackGround Thread:
for (model in modellist) {
model.testStr = anotherStringFromAlloc
}
At main thread:Only read property
At backGround thread: Write property content
Is this thread safe?
After read some source code, I have another question is:
Dose objc_retain and objc_release same obj is thread safe ?
As Petesh notes, this question is mostly answered in thread-safe retain/release, but I think just duping there will miss answering your specific problem.
You've explicitly asked for this property not to be thread-safe:
#property (nonatomic, copy) NSString *testStr;
The default behavior is atomic, which make it safe to read and write the pointer (not mutate the object) on different threads. You've marked this nonatomic, which disables that behavior. For more on this, see bbum's fairly canonical answer on atomic.
Your code, though, is also a good example of how relying on atomic reads alone to make code "thread-safe" can go wrong. This line is very unsafe:
if ((!model.testStr || ![model.testStr isKindOfClass:[NSString class]] || model.testStr.length == 0)) {
This makes three separate reads of model.testStr. Even with atomic, there's no promise that these are the same object if you might modify this on another thread. The fact that you test the class suggests that testStr might be something other than an NSString. If so, then model.testStr.length may crash with "does not respond to selector." If you use model.testStr inside the if block, then that may also be a different value than you tested.
Related
I get caught out way too many times by creating eg an NSMutableArray* myArray property and then forgetting to assign self.myArray = [NSMutableArray array]; in -init. My app of course never complains in such cases because [self.myArray addObject:foo] is perfectly legal if self.myArray is nil, so I'm left scratching my head and going "double you tee eff".
I realise this is a long shot, but is there an lldb attribute or property specifier that would cause obj-c to ensure that properties are non-nil after completing -init?
I don't believe there is a compiler flag that will help you, however you could change the semantics of your array access so it goes through your own methods instead of directly to the NSMutableArray.
So instead of
#interface MyClass : NSObject
#property NSMutableArray *array
#end
use:
#interface MyClass : NSObject
- (void)addObject:(id)object;
- (NSUInteger)objectCount;
- (id)objectAtIndex:(NSUInteger)index;
- (void)removeObjectAtIndex:(NSUInteger)index;
#end
and you can add whatever checks you like to those array access methods (as well as lazily creating the array, of course).
However, as you can see, this could be add significant effort just to solve a small issue, and I wouldn't do this myself :)
- (NSMutableArray*) myArray
{
NSAssert(nil != _myArray);
return _myArray;
}
You can write this implementation of myArray accessor.
Also you can add in yours class method something like that:
- (void) AssertValid
{
NSAssert(nil != _myArray);
}
I am not aware of such mechanism and don't think it exists, because it would make little practical sense as there are many classes whose properties are nil most of the time by design.
It is possible to perform this check using class_copyPropertyList() from objc-runtime and then reading every property by name (for example, using valueForKey:). In simplest case, you would create a category method like [self logNilProperties] on NSObject and call it at the end of init... methods of classes that you want to check.
What you want is not possible. It's a language feature. You can't just change the behavior of the language.
Probably the best solution you can get is to introduce unit tests for the values of your properties. Or asserts:
assert(self.property != nil)
Here is a small piece of code which is used to throw an Exception.
NSException *exception=[[NSException alloc]initWithName:#"no result" reason:#"array empty" userInfo:nil];
[exception raise];
The exception can be caught in the AppDelegate file
void exceptionHandler(NSException *exception){
}
Before this method write
NSSetUncaughtExceptionHandler(&exceptionHandler);
in the - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
Happy Coding :)
Given the following category definition how might I handle -dealloc both with and without ARC? I am currently using ARC and to the best of my knowledge and poking around in Instruments, the properties are being cleaned up but I am not 100% confident in that.
#interface NSObject (SuperUsefulThingIWishAllNSObjectsHad)
#property (nonatomic, copy) NSString *foo;
#end
#import <objc/runtime.h>
#implementation NSObject (SuperUsefulThingIWishAllNSObjectsHad)
static const void *MyPropertyKey = &MyPropertyKey;
#dynamic foo;
- (NSString *)foo
{
return objc_getAssociatedObject(self,
MyPropertyKey);
}
- (void)setFoo:(NSString *)foo
{
objc_setAssociatedObject(self,
MyPropertyKey,
foo,
OBJC_ASSOCIATION_COPY);
}
This is more for my own edification but if the solution isn't too hacky I may have some places I actually want to use this.
You don't need to do anything special in dealloc to “clean up” an associated object. The runtime takes care of it for you. This is independent of ARC.
If you're not using ARC, you need to be sure to call [super dealloc] in your own dealloc overrides. But you need to do that regardless of your use of associated objects, and the compiler will warn you if you forget.
UPDATE
In response to your comment: You're right that the Objective-C Runtime Reference doesn't explicitly say the associated object is released (if appropriate based on the association policy) when the main object is deallocated. But that is the only reasonable action, because the point of an associated object is to attach a subordinate object to a main object without changing the main object's source code.
Anyway, the source code of the Objective-C runtime is open source, so we can inspect it to verify that this is indeed what's implemented.
Look at NSObject.mm and you'll see that -[NSObject dealloc] calls _objc_rootDealloc, which calls object_dispose.
The object_dispose function is in objc-runtime-new.mm, and it calls objc_destructInstance, which calls _object_remove_assocations.
The _object_remove_assocations function (yes, it has a typo in the source code) is in objc-references.mm. It removes all objects associated with the object being deallocated, releasing them if appropriate. If you look at objc_removeAssociatedReferences, which is part of the public API and is defined in objc-runtime.m, you 'll see that it also calls _object_remove_assocations.
I have a property that holds a Core Foundation object, specifically a CFHTTPMessageRef. I've tried using the attribute((NSObject)) macro to tell the compiler to treat the referenced object as a normal NSObject and handle the retaining and releasing of that object for me rather than having to CFRelease myself. I've tried changing the property to weak instead of strong, but nothing seems to work, the static analyzer still tells me I have a memory leak, and from the looks of the output from CFGetRetainCount, it would that it's right. Does anyone know why my property would cause a memory leak:
typedef __attribute__((NSObject)) CFHTTPMessageRef HTTPMessageRef;
#interface ABRemoteConnection : NSObject
#property (strong) HTTPMessageRef message;
#end
- (void)dataReceived:(NSNotification *)notification {
self.message = CFHTTPMessageCreateEmpty(kCFAllocatorDefault, TRUE);
// do some stuff and if the message is complete, use it and release the
// message object
if (messageIsComplete(self.message)) {
self.message = NULL;
}
}
From the documentation, it looks like __attribute__((NSObject)) is only meant to be used with retain.
But switching strong to retain means you're now adding another ref which the prop is going to manage for you; there's still the original ref that you have to CFRelease.
If you think about it, this makes sense. Imagine doing the same thing with a property(retain) NSObject *:
- (void)dataReceived:(NSNotification *)notification {
self.o = [[NSObject alloc] init];
}
This works fine—but only because ARC sees the alloc and automatically inserts a corresponding release for you at the end of the scope. With a CF___Create function, there's no automatic CFRelease at the end of the scope, so you have to manually write one.
If you really want HTTPMessageRef to be as convenient as, say, NSDictionary, it can't just be a typedef; it has to be a toll-free bridged class.
I using Test Driven Development in Objective-C for iOS and Mac OS X development, and I want to be able to write tests that can verify that objects I create with class factory methods return autorelease objects.
How can someone write a test that verifies a provided object is autorelease?
In short, you can't. There is no way to know the autorelease state of an object.
In some cases, you can infer whether an object was placed in an autorelease pool. The idea is declaring a pointer to an object, instantiating it within an #autoreleasepool block, and then verifying that it had dealloc called after the end of the block.
Through whatever combination of swizzling or overriding dealloc you choose, you must first provide a way to verify that dealloc has been called. I wrote an NSObject category with the following interface and implementation, that provides a deallocationDelegate property that will receive a message of handleDeallocation: when the object is deallocated.
#interface NSObject (FunTimes)
#property (nonatomic, assign) id deallocationDelegate;
#end
#implementation NSObject (FunTimes)
+ (void)load
{
Class klass = [NSObject class];
SEL originalSelector = #selector(dealloc);
Method originalMethod = class_getInstanceMethod(klass, originalSelector);
SEL replacementSelector = #selector(funDealloc);
Method replacementMethod = class_getInstanceMethod(klass, replacementSelector);
if(class_addMethod(klass, originalSelector, method_getImplementation(replacementMethod), method_getTypeEncoding(replacementMethod)))
{
class_replaceMethod(klass, replacementSelector, method_getImplementation(originalMethod), method_getTypeEncoding(originalMethod));
}
else
{
method_exchangeImplementations(originalMethod, replacementMethod);
}
}
- (void)funDealloc
{
if (self.deallocationDelegate)
[self.deallocationDelegate performSelector:#selector(handleDeallocation:) withObject:self];
[self funDealloc];
}
static char myKey;
- (void)setDeallocationDelegate:(id)deallocationDelegate
{
objc_setAssociatedObject(self, &myKey, deallocationDelegate, OBJC_ASSOCIATION_ASSIGN);
}
- (id)deallocationDelegate
{
return objc_getAssociatedObject(self, &myKey);
}
#end
I ran some test code in my application delegate just to see if it works. I declared an NSMutableArray instance designed to hold NSValue instances derived from the pointers of objects calling -handleDeallocation, which I implement as shown:
- (void)handleDeallocation:(id)toDie
{
NSValue *pointerValue = [NSValue valueWithPointer:toDie];
[self.deallocatedPointerValues addObject:pointerValue];
}
Now, here's a snippet of what I ran. SomeClass is an NSObject subclass with no additional properties or methods.
self.deallocatedPointerValues = [NSMutableArray array];
SomeClass *arsc = nil;
#autoreleasepool {
arsc = [[[SomeClass alloc] init] autorelease];
arsc.deallocationDelegate = self;
NSValue *prePointerValue = [NSValue valueWithPointer:arsc];
BOOL preDeallocated = [self.deallocatedPointerValues containsObject:prePointerValue];
NSLog(#"PreDeallocated should be no is %d",preDeallocated);
}
NSValue *postPointerValue = [NSValue valueWithPointer:arsc];
BOOL postDeallocated = [self.deallocatedPointerValues containsObject:postPointerValue];
NSLog(#"Post deallocated should be yes is %d",postDeallocated);
In this case, it can be verified that the object pointed to by arsc (which stands for auto released SomeClass) has been deallocated due to ending the #autoreleasepool block.
There are several significant limitations to the this approach. One, this cannot work when other messages of retain may be sent to your object that is returned from your factory method. Also, and this should go without saying, swizzling dealloc should only be done in experimental settings, and I think some would argue that it shouldn't be swizzled in testing (obviously it shouldn't be swizzled in production!). Finally, and more significantly, this doesn't work well with Foundation objects such as NSString that have been optimized in ways that it's not always clear whether you are creating a new instance or not. So this is most appropriate, if at all, for your own custom objects.
As a final word, I don't think it's practical to do this really. I felt it was more work than it was worth and is so narrowly applicable as the make spending time learning instruments better to be a far better investment when it comes to memory management. And, of course, with ARC's ascendency, this approach is archaic from the start. Regardless, if you do have need to write such tests, and can work around the limitations here, feel free to adapt this code. I'd be curious to see how it pans out in an actual testing environment.
I commend your dedication to TDD. But memory management is an area where you simply have to follow well-established conventions: "When returning an object, it needs to take care of its own lifetime." My unit tests catch me when I accidentally over-release something, but they won't catch a leak. For that, I rely first on Analyze, then on running the Leaks instrument.
This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Atomic vs nonatomic properties
I just want to know what is the differneve between theses two lines of code :
#property(nonatomic, retain) NSString *str;
and
#property(atomic, retain) NSString *str;
Thanx,
Regards,
tek3
Atomic properties are necessary in a reference counted multi threaded environment in order to stop objects from disappearing before a thread has a chance to retain them.
Consider the naive implementation of a get accessor:
#interface MyObject : NSObject
{
id myPropertyIVar;
}
-(id) myProperty;
#end
#implementation MyObject
-(id) myProperty
{
return myPropertyIvar;
}
// other stuff
#end
This is all fine except that if you release the instance of MyObject before retaining the returned value from -myProperty the returned value may well be deallocated. For this reason, it is safer to implement -myProperty like this:
-(id) myProperty
{
return [[myPropertyIvar retain] autorelease];
}
This is now completely safe in a single threaded environment.
Unfortunately, in a multithreaded environment there is a race condition. If the thread is interrupted at any time before the retain has incremented the retain count, either of the following will cause you to receive a garbage pointer:
the instance of MyObject is released and deallocated by another thread causing the ivar to be released and deallocated
myProperty is reassigned by another thread causing the old version to be released and deallocated
For this reason, all accesses to the property must be protected by a lock. The get accessor looks something like this.
-(id) myProperty
{
// lock
return [[myPropertyIvar retain] autorelease];
// unlock
}
The set accessor is similarly protected and so is the release in -dealloc
The Apple docs explain all this very well. To learn about properties, including their atomicity, read this page.