I'm using a framework that uses a huge amount of block arguments to emit events. Due to licensing I can't release code samples, but I can still get my point across with similar code. Lets say you have the following code:
- (void)begin
{
[MyService doSomething:^{
NSLog(#"Done.");
}];
}
This is fine, but the methods I'm dealing with have 14 block arguments, most of which take several parameters so it makes it very hard to read and difficult to test without creating repetitive boiler-plate code.
Is there a way I can point a block to an instance's method, something like:
- (void)doSomethingDelegate
{
NSLog(#"Done.");
}
- (void)begin
{
[MyService doSomething:CALLBACK(self, #selector(doSomethingDelegate))];
}
Where CALLBACK is a macro or native construct. Is this possible?
No, but you can declare local blocks:
- (void)begin
{
void (^callback)() = ^{ NSLog(#"Done."); };
[MyService doSomething:callback];
}
You could extend that to:
- (void)callbackImpl {
NSLog(#"Done.");
}
- (void)begin {
void (^callback)() = ^() { [self callbackImpl]; };
[MyService doSomething:callback];
}
And you could imagine a macro of the sort:
#define CALLBACK(name) void (^name)() = ^{ [self name##Impl]; };
It gets a little messier when you have arguments to the block, and you need to consider if you want a strong or weak reference to self in those blocks...
Since I also have to worry about arguments that are in a different from this is the best solution I've found so far:
#define wrapper(args, method) ^args { [self method]; }
- (void)onUpdatingDeviceWithMessage:(NSString *)message progress:(float)progress
{
}
- (void)begin
{
[MyService ...
onUpdatingDevice:wrapper((NSString *message, float progress),
onUpdatingDeviceWithMessage:message progress:progress)
}
Related
I'm working on a simple instagram project now.
for several occasions I've encountered the same problem.
To work with instagram I use InstagramKit Engine. It has some preset (void)s to make life easier. However I'm always stuck at the same problem.
Let's say we've got this:
- (void)getSelfUserDetails
{
[[InstagramEngine sharedEngine] getSelfUserDetailsWithSuccess:^(InstagramUser *userDetail) {
NSLog(#"%#",userDetail);
} failure:^(NSError *error) {
}];
}
Here userDetail is used inside of the "Success". And it works nice. What I need is to somehow save it after the block is done.
I've tried several things from creating a property to store the userDetails up to making my own method to return the userDetails. The same trouble with saving ints, NSStrings etc..
I think I'm missing some easy way out.
Show it to me please.
You need to capture an object in the block that you can send the response object.
This can be self.
-(void)processUserDetails:(InstagramUser *) userDetail
{
//....
}
- (void)getSelfUserDetails
{
[[InstagramEngine sharedEngine] getSelfUserDetailsWithSuccess:^(InstagramUser *userDetail) {
[self processUserDetails: userDetail];
} failure:^(NSError *error) {
}];
}
You could create a property to hold the Instagram user that you find and assign it to it in the success block:
#property (nonatomic) InstagramUser *myUser;
- (void)getSelfUserDetails
{
[[InstagramEngine sharedEngine] getSelfUserDetailsWithSuccess:^(InstagramUser *userDetail) {
NSLog(#"%#",userDetail);
self.myUser = userDetail;
} failure:^(NSError *error) {
}];
}
This is a good use for an NSNotification (since the call above happens asynchronously).
You could call it like:
[[NSNotificationCenter defaultCenter]
postNotificationName:#"TestNotification"
object:self
userInfo:#{ #"userDetail" : userDetail }
];
And then get that userInfo data back with whatever method is listening for that event.
I've got an Objective-c app with several blocks of code where I only want one thread to be able to access it at a time. Using a #synchronized(self) block works fine for that.
However, I've got one block where I want it to skip the block, if another thread is in one of the #synchronized blocks, rather than wait. Is there a way to simply test if self (or whatever my lock object is) is being held by another synchronized block?
// block 1 - wait until lock is available
#synchronized(self) {
...
}
...
// block 2 - wait until lock is available
#synchronized(self) {
...
}
...
// block 3 - wait until lock is available
#synchronized(self) {
...
}
...
// block 4 - skip if lock is not immediately available - no waiting!
howDoISkipIfLockIsNotAvailable(self) {
...
}
What you want to achieve is possible when using NSLock or NSRecursiveLock instead of the #synchronized syntax sugar. They key feature it offers is the tryLock method:
NSRecursiveLock *lock = [[NSRecursiveLock alloc] init];
[lock lock];
#try {
// ... do synchronized stuff
}
#finally {
[lock unlock];
}
if ([lock tryLock]) {
#try {
// do synchronized stuff if possible
}
#finally {
[lock unlock];
}
}
I'm playing around with blocks in Objective-C, trying to come up with a reusable mechanism that will take an arbitrary block of code and a lock object and then execute the block of code on a new thread, synchronized on the provided lock. The idea is to come up with a simple way to move all synchronization overhead/waiting off of the main thread so that an app's UI will always be responsive.
The code I've come up with is pretty straightforward, it goes like:
- (void) executeBlock: (void (^)(void))block {
block();
}
- (void) runAsyncBlock: (void (^)(void))block withLock:(id)lock {
void(^syncBlock)() = ^{
#synchronized(lock) {
block();
}
};
[self performSelectorInBackground:#selector(executeBlock:) withObject:syncBlock];
}
So for example, you might have some methods that go like:
- (void) addObjectToSharedArray:(id) theObj {
#synchronized(array) {
[array addObject: theObj];
}
}
- (void) removeObjectFromSharedArray:(id) theObj {
#synchronized(array) {
[array removeObject: theObj];
}
}
Which works fine, but blocks the calling thread while waiting for the lock. These could be rewritten as:
- (void) addObjectToSharedArray:(id) theObj {
[self runAsyncBlock:^{
[array addObject: theObj];
} withLock: array];
}
- (void) removeObjectFromSharedArray:(id) theObj {
[self runAsyncBlock: ^{
[array removeObject: theObj];
} withLock:array];
}
Which should always return immediately, since only the background threads will compete over the lock.
The problem is, this code crashes after executeBlock: without producing any output, error message, crash log, or any other useful thing. Is there something fundamentally flawed in my approach? If not, any suggestions with respect to why this might be crashing?
Edit:
Interestingly, it works without crashing if I simply do:
- (void) runAsyncBlock: (void (^)(void))block withLock:(id)lock {
void(^syncBlock)() = ^{
#synchronized(lock) {
block();
}
};
syncBlock();
}
But of course this will block the calling thread, which largely defeats the purpose. Is it possible that blocks do not cross thread boundaries? I would think not, since that would largely defeat the purpose of having them in the first place.
remember to call [block copy] otherwise it is not correctly retained because block are created on stack and destroyed when exit scope and unless you call copy it will not move to heap even retain is called.
- (void) runAsyncBlock: (void (^)(void))block withLock:(id)lock {
block = [[block copy] autorelease];
void(^syncBlock)() = ^{
#synchronized(lock) {
block();
}
};
syncBlock = [[syncBlock copy] autorelease];
[self performSelectorInBackground:#selector(executeBlock:) withObject:syncBlock];
}
i have a method, in which i want to accomplish a given task, however, the asynchronous commands and delegates made it difficult
i can do this :
- (void) fooPart1
{
...
SomeAssynchronousMethos * assync = [[SomeAssynchronousMethos alloc] init];
assync.delegate = self;
[assync start];
}
- (void) fooPart2
{
...
possibly some other assync
}
- (void)someAssynchronousMethosDelegateDidiFinish
{
[self fooPart2];
}
But isn't there a way to do smith. like this
- (void) foo
{
...
SomeAssynchronousMethos * assync = [[SomeAssynchronousMethos alloc] init];
assync.delegate = self;
[assync start];
wait for signal, but class is not blocked
...
possibly some other assync
}
- (void)someAssynchronousMethosDelegateDidiFinish
{
continue in foo after [assync start]
}
I don't like the idea of splitting a function to 2 or more parts, but is this the way how it is done in cocoa? or is there a better practice?
why i dont like this concept and searching for a better way of doing it :
lets say, i want to use a variable only for compleating a task - if i have everything in one function, i just use it, and than the var dies as i leave the function, if its split, i have to keep the var somehow around, until it doesnt finish
the code becomes fragmented and more difficult to read and maintain
may lead to bug
i end up with a set of part function, that needs to be called in precise order to accomplish one task (for which one function would be more suitable)
i used to make a thread and do only synchronous calls there, but not everything supports a synchronous call
what would be realy nice, is to have smth, like
- (void) foo
{
...
int smth = 5;
SomeAssynchronousMethos * assync = [[SomeAssynchronousMethos alloc] init];
assync.delegate = self;
#freez([assync start]);
// when freez - the local function variables are frozen
// (next commands in function are not excuted until unfreez)
// from outer look, it looks like the function finished
// however when unfreeze, it is called from this point on
//int smth is still 5
}
- (void)someAssynchronousMethosDelegateDidiFinish
{
#unfreez([assync start]);
}
when the execution would reach freez, it would store all local vars allocated in function and when called unfreez, it would continue from that point on, when it was freez with that command
This seems like an ideal application of a completion handler block.
Alter your start method to take a parameter which is a block and call it like so:
- (void) fooPart1
{
...
SomeAssynchronousMethos * assync = [[SomeAssynchronousMethos alloc] init];
[assync startOnComplete: ^(NSError* error) // example, you can have any params or none
{
// handle error if not nil
if (error != nil)
{
// do something with it
}
// code to do on completion
}];
}
Your start method would look something like this
-(void) startOnComplete: (void(^)(NSError*)) completionBlock
{
// copy the block somewhere
theSavedCompletionBlock = [completionBlock copy];
// kick off async operation
}
-(void) someMethodThatRunsAttheEndOfTheAsyncOp
{
theSavedCompletionBlock(nilOrError);
[theSavedCompletionBlock release];
}
My app is crashing in iOS 5 because I have some code that is calling UIKit instances from a secondary thread. You know you have this problem when you see the following error:
bool _WebTryThreadLock(bool), 0x811bf20: Multiple locks on web thread not allowed! Please file a bug. Crashing now…
So my question is what are some ways that I can find the code that is calling the UIKit instances from a secondary thread?
Here are some things I’ve tried already:
Commented out blocks that could be violating the rule
Added assert([NSThread isMainThread]) in places that might be processing in secondary thread
Added a symbolic breakpoint for _WebTryThreadLock
These things have helped me to find problem areas. However, in my final crash the _WebTryThreadLock breakpoint has no stack trace in any of the other threads. So, how I can find the code that causing the problem without a stack trace?
Thanks for your time!
Your assert() is probably the most valuable tool in this. I've been known to put a similar assertion at the beginning of every method in my Controller classes. If that doesn't find it, I add the assertion to my View classes. If that doesn't find it, I add it to any Model classes that I think are main-thread only.
To #craig's comment, the fact that it claims to be an internal bug might be accurate. But I think you're on the right path to closely examine your own code first.
I adapted the PSPDFUIKitMainThreadGuard.m to allow one to not have to worry about these things. Here: https://gist.github.com/k3zi/98ca835b15077d11dafc :
#import <objc/runtime.h>
#import <objc/message.h>
// Compile-time selector checks.
#define PROPERTY(propName) NSStringFromSelector(#selector(propName))
// A better assert. NSAssert is too runtime dependant, and assert() doesn't log.
// http://www.mikeash.com/pyblog/friday-qa-2013-05-03-proper-use-of-asserts.html
// Accepts both:
// - PSPDFAssert(x > 0);
// - PSPDFAssert(y > 3, #"Bad value for y");
#define PSPDFAssert(expression, ...) \
do { if(!(expression)) { \
NSLog(#"%#", [NSString stringWithFormat: #"Assertion failure: %s in %s on line %s:%d. %#", #expression, __PRETTY_FUNCTION__, __FILE__, __LINE__, [NSString stringWithFormat:#"" __VA_ARGS__]]); \
abort(); }} while(0)
///////////////////////////////////////////////////////////////////////////////////////////
#pragma mark - Helper for Swizzling
BOOL PSPDFReplaceMethodWithBlock(Class c, SEL origSEL, SEL newSEL, id block) {
PSPDFAssert(c && origSEL && newSEL && block);
Method origMethod = class_getInstanceMethod(c, origSEL);
const char *encoding = method_getTypeEncoding(origMethod);
// Add the new method.
IMP impl = imp_implementationWithBlock(block);
if (!class_addMethod(c, newSEL, impl, encoding)) {
NSLog(#"Failed to add method: %# on %#", NSStringFromSelector(newSEL), c);
return NO;
}else {
// Ensure the new selector has the same parameters as the existing selector.
Method newMethod = class_getInstanceMethod(c, newSEL);
PSPDFAssert(strcmp(method_getTypeEncoding(origMethod), method_getTypeEncoding(newMethod)) == 0, #"Encoding must be the same.");
// If original doesn't implement the method we want to swizzle, create it.
if (class_addMethod(c, origSEL, method_getImplementation(newMethod), encoding)) {
class_replaceMethod(c, newSEL, method_getImplementation(origMethod), encoding);
}else {
method_exchangeImplementations(origMethod, newMethod);
}
}
return YES;
}
// This installs a small guard that checks for the most common threading-errors in UIKit.
// This won't really slow down performance but still only is compiled in DEBUG versions of PSPDFKit.
// #note No private API is used here.
__attribute__((constructor)) static void PSPDFUIKitMainThreadGuard(void) {
#autoreleasepool {
for (NSString *selStr in #[PROPERTY(setNeedsLayout), PROPERTY(setNeedsDisplay), PROPERTY(setNeedsDisplayInRect:)]) {
SEL selector = NSSelectorFromString(selStr);
SEL newSelector = NSSelectorFromString([NSString stringWithFormat:#"pspdf_%#", selStr]);
if ([selStr hasSuffix:#":"]) {
PSPDFReplaceMethodWithBlock(UIView.class, selector, newSelector, ^(__unsafe_unretained UIView *_self, CGRect r) {
if(!NSThread.isMainThread){
dispatch_async(dispatch_get_main_queue(), ^{
((void ( *)(id, SEL, CGRect))objc_msgSend)(_self, newSelector, r);
});
}else{
((void ( *)(id, SEL, CGRect))objc_msgSend)(_self, newSelector, r);
}
});
}else {
PSPDFReplaceMethodWithBlock(UIView.class, selector, newSelector, ^(__unsafe_unretained UIView *_self) {
if(!NSThread.isMainThread){
dispatch_async(dispatch_get_main_queue(), ^{
((void ( *)(id, SEL))objc_msgSend)(_self, newSelector);
});
}else
((void ( *)(id, SEL))objc_msgSend)(_self, newSelector);
});
}
}
}
}
It automatically kicks calls into the main thread and thus you wouldn't even have to do anything but plop the code in.
This problem comes because you want to access to UI from secondary thread somehow, it can from webview of whatever else. It is not permitted because UIKit is not thread safe and can be accessed only from MainThread.
The very first thing you can do is to change your thread call to [self performSelectorOnMainThread:#selector(myMethod) withObject:nil waitUntilDone:NO]; (look for documentation).
In case when you have no other choice you can use GCD(Grand Central Dispathc)...
This code (just add to project and compile this file without ARC) causes assertions on UIKit access outside the main thread: https://gist.github.com/steipete/5664345
I've just used it to pickup numerous UIKit/main thread issues in some code I've just picked up.