From wikipedia explanation about thread-safety,thread safe codes can be run in multithreads.
For iOS 3.x, UIKit is not thread safety, since 4.0, UIKIt is thread safety.
In our implementations, we can use synchronized to build thread safety codes. My questions about thread safety are:
1). How to detect thread safety coding issue with instruments tools or other ways ?
2). Any good practices to write thread safety codes for iOS development ?
since 4.0, UIKIt is thread safety.
Basically, UIKit is not thread-safe. Only drawing to a graphics context in UIKit is thread-safe since 4.0.
1) Hmm, I also want to know about that :-)
2) How about Concurrency Programming Guide?
To make a non thread-safe object thread safe, consider using a proxy (see the code below). I use it for example for NSDateFormatter, which is not a thread safe class, when parsing data in a background thread.
/**
#brief
Proxy that delegates all messages to the specified object
*/
#interface BMProxy : NSProxy {
NSObject *object;
BOOL threadSafe;
}
#property(atomic, assign) BOOL threadSafe;
- (id)initWithObject:(NSObject *)theObject;
- (id)initWithObject:(NSObject *)theObject threadSafe:(BOOL)threadSafe;
#end
#implementation BMProxy
#synthesize threadSafe;
- (id)initWithObject:(NSObject *)theObject {
object = [theObject retain];
return self;
}
- (id)initWithObject:(NSObject *)theObject threadSafe:(BOOL)b {
if ((self = [self initWithObject:theObject])) {
self.threadSafe = b;
}
return self;
}
- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector {
return [object methodSignatureForSelector:aSelector];
}
- (void)forwardInvocation:(NSInvocation *)anInvocation {
if (self.threadSafe) {
#synchronized(object) {
[anInvocation setTarget:object];
[anInvocation invoke];
}
} else {
[anInvocation setTarget:object];
[anInvocation invoke];
}
}
- (BOOL)respondsToSelector:(SEL)aSelector {
BOOL responds = [super respondsToSelector:aSelector];
if (!responds) {
responds = [object respondsToSelector:aSelector];
}
return responds;
}
- (void)dealloc {
[object release];
[super dealloc];
}
#end
Related
I have an SKShapeNode and I am setting the shape as a RoundedRectangle but when I analyze the code I am receiving a warning that states there is a potential leak of an object.
My interfaceFile is as follows:
#import <SpriteKit/SpriteKit.h>
#interface letterSpace : SKShapeNode
-(instancetype) initWithCharacter:(NSString *)character xPosition:(float)x yPosition:(float)y device:(NSString *)device;
#property(nonatomic, assign) BOOL occupied;
#property(nonatomic, assign) BOOL whiteSpace;
#property(nonatomic, retain) NSString *character;
#property (atomic) float secondLineX;
#property (atomic) float secondLineY;
#end
And then the implementation is
#import "letterSpace.h"
#implementation letterSpace
-(instancetype) initWithCharacter:(NSString *)character xPosition:(float)x yPosition:(float)y device:(NSString *)device{
self = [super init];
if(self){
if ([device isEqualToString:#"IPHONE"]) {
[self setPath:CGPathCreateWithRoundedRect(CGRectMake(0, 0, 30, 2), 1, 1, nil)]; // Potential Leak of an object on this line
_secondLineX = 36*8;
_secondLineY = -36;
}else{
[self setPath:CGPathCreateWithRoundedRect(CGRectMake(0, 0, 60, 3.5), 1, 1, nil)]; // Potential Leak of an object on this line
_secondLineX = 575;
_secondLineY = -71;
}
self.strokeColor = [UIColor clearColor];
if ([character isEqual: #" "]) {
self.occupied = TRUE;
self.fillColor = [UIColor clearColor];
self.character = character;
self.whiteSpace = TRUE;
}else{
self.whiteSpace = FALSE;
self.occupied = FALSE;
self.fillColor = [UIColor colorWithRed:80.0f/255.0f
green:227.0f/255.0f
blue:194.0f/255.0f
alpha:1];
}
if (y <8) {
self.position = CGPointMake(x, 0);
}
else{
self.position = CGPointMake(x - _secondLineX, _secondLineY);
}
self.name = character;
}
return self;
}
#end
Any ideas how to solve this leak? or what's causing it?
When you use Core Foundation objects, you own an object if you call function that*:
have “Create” embedded in the name;
have "Copy" embedded in the name;
*however, this does not apply to a methods that return Objective-C objects.
If you are an owner of an object, you must relinquish ownership when you have finished using it using CFRelease (or the corresponding type-specific variants).
In ARC environment, the compiler does not automatically manage the lifetimes of Core Foundation objects. You must call CFRetain and CFRelease (or the corresponding type-specific variants)
Also you need to tell the compiler about the ownership of the object if you cast between Objective-C and Core Foundation objects:
__bridge transfers a pointer between Objective-C and Core Foundation with no transfer of ownership;
__bridge_retained or CFBridgingRetain casts an Objective-C pointer to a Core Foundation pointer and also transfers ownership to you. You are responsible for calling CFRelease or a related function to relinquish ownership of the object;
__bridge_transfer or CFBridgingRelease moves a non-Objective-C pointer to Objective-C and also transfers ownership to ARC. ARC is responsible for relinquishing ownership of the object.
So, in your case:
path has a type of CGPathRef, which from a Core Graphics frameworks that adopts to Core Foundation memory management conventions. So, we apply the rule "If you call the method that have a "Create" embedded in the name - you own it". It is not matter whether it is Manual (in manual you must) or Automatic (ARC environment does not automatically manage the lifetimes of Core Foundation objects) Memory Management you must release this object.
CGPathRef path = CGPathCreateWithRoundedRect(CGRectMake(0, 0, 30, 2), 1, 1, nil);
[self setPath:path];
CGPathRelease(path);
or you can use Cocoa analogue bezierPathWithRoundedRect:(NSRect)rect xRadius:(CGFloat)xRadius yRadius:(CGFloat)yRadius.
Also, I would recommend you to use NULL instead of nil in CGPathCreateWithRoundedRect.
Memory Management Programming Guide for Core Foundation
Advanced Memory Management Programming Guide
Transitioning to ARC Release Notes
Generally speaking... in an NSManagedObject class, inside one of the setters for a given float dynamic property, is it OK to use the dot-syntax getters for other float dynamic properties of the same NSManagedObject within that setter? Or do I need to use KVC-compliant CoreData accessors any time I access a value, even if it's from a different method than the actual getter for the value being accessed? I would assume that calling the dot-syntax in this way would cause my other custom accessor to fire, which is OK with me, since inside that there are the proper KVC primitive accessors. But I've seemed to run into weird issues where the dot-syntax either simply fails, or seems to have unpredictable results, and I'm not sure if it's because of the fact I'm using the dot-syntax in an unsafe way, or if there's some other bug I haven't figured out yet.
Here's a code sample of something I'm talking about:
- (void)illTakeYouToTheWoodshed {
float h = self.SSx.floatValue/self.yourMomsCurrentWeightInTons.floatValue;
[self willChangeValueForKey:#"SSy"];
[self setPrimitiveValue:#(h) forKey:#"SSy"];
[self didChangeValueForKey:#"SSy"];
[self diagonal]; //makes sure nd gets set
}
- (void)setSSx:(NSNumber *)value{
[self willChangeValueForKey:#"SSx"];
[self setPrimitiveValue:value forKey:#"SSx"];
[self didChangeValueForKey:#"SSx"];
if(self.WorH==syanara || self.WorH == dude_wtf) {
if(self.SSy.floatValue != 0.0) {
[self doThatFunkyDance];
[self diagonal];
} else if (self.youBetcha.floatValue != 0.0) {
[self whatTheFrakDoesThisEvenDo];
}
} else if (self.WorH==fooBarTastic) {
if(self.yourMomsCurrentWeightInTons.floatValue != 0.0) {
[self illTakeYouToTheWoodshed];
}
} else {
NSLog(#"Escaped with salad not having been tossed.");
}
}
I want to add a KVO observation that removes itself after it fires once. I have seen lots of folks on StackOverflow doing stuff like this:
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
{
if ([keyPath isEqualToString:#"myKeyPath"])
{
NSLog(#"Do stuff...");
[object removeObserver:self forKeyPath:#"isFinished"];
}
else
{
[super observeValueForKeyPath:keyPath ofObject:object change:change context:context];
}
}
This seems plausible, but I'm aware that calling -removeObserver:forKeyPath: from within -observeValueForKeyPath:... can be lead to non-deterministic crashes that are hard to debug. I also want to be sure this observation only gets called once (or not at all if the notification is never sent). What's a good way to do this?
I'm answering my own question here because I've seen the pattern in the question all over the place, but haven't had a reference to a good example of a better way. I've lost days, if not weeks, of my life to debugging problems ultimately found to be caused by adding and removing observers during the delivery of KVO notifications. Without warranty, I present the following implementation of a one-shot KVO notification that should avoid the problems that come from calling -addObserver:... and -removeObserver:... from inside -observeValueForKeyPath:.... The code:
NSObject+KVOOneShot.h:
typedef void (^KVOOneShotObserverBlock)(NSString* keyPath, id object, NSDictionary* change, void* context);
#interface NSObject (KVOOneShot)
- (void)addKVOOneShotObserverForKeyPath:(NSString *)keyPath options:(NSKeyValueObservingOptions)options context:(void *)context block: (KVOOneShotObserverBlock)block;
#end
NSObject+KVOOneShot.m: (Compile with -fno-objc-arc so we can be explicit about retain/releases)
#import "NSObject+KVOOneShot.h"
#import <libkern/OSAtomic.h>
#import <objc/runtime.h>
#interface KVOOneShotObserver : NSObject
- (instancetype)initWithBlock: (KVOOneShotObserverBlock)block;
#end
#implementation NSObject (KVOOneShot)
- (void)addKVOOneShotObserverForKeyPath:(NSString *)keyPath options:(NSKeyValueObservingOptions)options context:(void *)context block: (KVOOneShotObserverBlock)block
{
if (!block || !keyPath)
return;
KVOOneShotObserver* observer = nil;
#try
{
observer = [[KVOOneShotObserver alloc] initWithBlock: block];
// Tie the observer's lifetime to the object it's observing...
objc_setAssociatedObject(self, observer, observer, OBJC_ASSOCIATION_RETAIN);
// Add the observation...
[self addObserver: observer forKeyPath: keyPath options: options context: context];
}
#finally
{
// Make sure we release our hold on the observer, even if something goes wrong above. Probably paranoid of me.
[observer release];
}
}
#end
#implementation KVOOneShotObserver
{
void * volatile _block;
}
- (instancetype)initWithBlock: (KVOOneShotObserverBlock)block
{
if (self = [super init])
{
_block = [block copy];
}
return self;
}
- (void)dealloc
{
[(id)_block release];
[super dealloc];
}
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
{
KVOOneShotObserverBlock block = (KVOOneShotObserverBlock)_block;
// Get the block atomically, so it can only ever be executed once.
if (block && OSAtomicCompareAndSwapPtrBarrier(block, NULL, &self->_block))
{
// Do it.
#try
{
block(keyPath, object, change, context);
}
#finally
{
// Release it.
[block release];
// Remove the observation whenever...
// Note: This can potentially extend the lifetime of the observer until the observation is removed.
dispatch_async(dispatch_get_main_queue(), ^{
[object removeObserver: self forKeyPath: keyPath context: context];
});
// Don't keep us alive any longer than necessary...
objc_setAssociatedObject(object, self, nil, OBJC_ASSOCIATION_RETAIN);
}
}
}
#end
The only potential hitch here is that the dispatch_async deferred removal may marginally extend the lifetime of the observed object by one pass of the main run loop. This shouldn't be a big deal in the common case, but it's worth mentioning. My initial thought was to remove the observation in dealloc, but my understanding is that we don't have a strong guarantee that the observed object will still be alive when the -dealloc of KVOOneShotObserver is called. Logically, that should be the case, since the observed object will have the only "seen" retain, but since we pass this object into API whose implementation we can't see, we can't be completely sure. Given that, this feels like the safest way.
Grand Central Dispatch is great and reduces the amount of code but why I cannot run something on a background thread?
I have made a sample application to show what I mean (none of the commented work):
- (IBAction)performSel {
[self performSelectorInBackground:#selector(doStuff) withObject:nil];
[NSThread sleepForTimeInterval:3];
[[self.view.subviews lastObject] removeFromSuperview];
}
- (IBAction)gcd {
dispatch_async(dispatch_queue_create("myGCDqueue", NULL), ^(void) {
//dispatch_sync(dispatch_queue_create("myGCDqueue", NULL), ^(void) {
//dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(void) {
//dispatch_sync(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(void) {
//dispatch_async(dispatch_get_main_queue(), ^(void) {
//dispatch_sync(dispatch_get_main_queue(), ^(void) {
[self doStuff]; // only for readability, will move the code on success
});
[NSThread sleepForTimeInterval:3];
[[self.view.subviews lastObject] removeFromSuperview];
}
- (void)doStuff {
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc]init];
UIView *abortingView = [[UIView alloc]initWithFrame: self.view.bounds];
abortingView.backgroundColor = [UIColor whiteColor];
abortingView.alpha = 0.7;
[self.view insertSubview:abortingView atIndex:10];
[abortingView release];
[pool drain];
}
the [NSThread sleepForTimeInterval:3]; is to simulate a default UI functionality. For example if someone is switching from one navigation view to another.
Simply copy the code in a new view based application, create two buttons and connect them.
UIKit classes should be used only from an application’s main thread. (From iOS4, drawing to a graphics context is thread-safe.) You can't use UIKit stuff in a background thread.
Thus, you can only use dispatch_async(dispatch_get_main_queue(), block) in this situation.
dispatch_async(dispatch_get_main_queue(), ^(void) {
It will invoke the block on the main thread in the runloop of the main thread.
dispatch_async(dispatch_queue_create("myGCDqueue", NULL), ^(void) {
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(void) {
It will invoke the block in a background thread. You can't use it because you want to use UIKit in the block. And be careful dispatch_async(dispatch_queue_create(, it might cause memory leak, you have to release the serial queue that is created by dispatch_queue_create.
dispatch_sync(dispatch_queue_create("myGCDqueue", NULL), ^(void) {
dispatch_sync(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(void) {
dispatch_sync waits until the block is done.
dispatch_sync(dispatch_get_main_queue(), ^(void) {
It causes DEADLOCK.
Dear community.
I have NSOperation subclass with property:
#property(readwrite, getter=isCancelled) BOOL cancelled;
from where i was create object of subclass NSObject (from init):
database = [[[MySQLIXC alloc] initWithQuene:iQuene andCarrier:startForCarrier withState:cancelled] retain];
In this custom object i try to declare local iVar:
#interface MySQLIXC : NSObject {
BOOL _currentQueueStatus;
In init:
- (id)initWithQuene:(NSUInteger)quene andCarrier:(NSString *)carrierName withState:(BOOL)currentQueueStatus;
_currentQueueStatus = currentQueueStatus;
But currentQueueStatus allways null.
Can somebody suggest a problem location?
1) you should avoid re-declaring implemented subclass interface for your additions (e.g. -[NSOperation isCancelled] exists)
2) it is very unusual to start with two retain counts:
database = [[MySQLIXC alloc] initWithQuene:iQuene andCarrier:startForCarrier withState:cancelled];
[otherThingThatHoldsAReference setDatabase:database];
instead of:
database = [[[MySQLIXC alloc] initWithQuene:iQuene andCarrier:startForCarrier withState:cancelled] retain];
3) _currentQueueStatus is not null it's a BOOL, which is a signed char. it should be 0 (NO) or 1 (YES).
4) what is currentQueueStatus? more code would help you receive more specific answers.
EDIT: updated for clarification in response to comments
/* things would look different if you subclass MONOperation */
#interface MONOperation : NSOperation
{
#private
MySQLIXC * sqlIxc;
BOOL didCancelDatabaseRequest;
}
/*
do not use isCancelled for your name - NSOperation declares this method, and
its implementation is well defined. this would override the implementation
and likely cause runtime errors.
specifically, NSOperation/NSOperationQueue uses cancel and isCancelled in its
interface and state. if you must cancel, then call cancel from cancelDatabaseRequest.
you may override cancel, but call [super cancel] in your implementation.
*/
#property (readonly) BOOL didCancelDatabaseRequest;
#property (retain) MySQLIXC * sqlIxc;
#end
#implementation MONOperation
/* ... */
- (BOOL)didCancelDatabaseRequest
{
return didCancelDatabaseRequest;
}
- (void)cancelDatabaseRequest /* in this example, there is no sense making cancelDatabaseRequest publicly visible */
{
/* for example */
assert(self.sqlIxc);
self.sqlIxc = nil;
didCancelDatabaseRequest = YES;
[self cancel]; /* do this rather than overriding NSOperation's cancellation interfaces in your subclass */
}
- (void)main
{
NSAutoreleasePool * pool = [NSAutoreleasePool new];
assert(self.sqlIxc);
self.sqlIxc.doStuff;
if (self.sqlIxc.didTimeout || self.sqlIxc.couldNotAccessFile) {
[self cancelDatabaseRequest];
}
else {
/* use the result */
}
[pool release];
}
#end