TMCache - using Blocks to Monitor Cache Events - ios

From the documentation:
/**
A block to be executed just after an object is added to the cache. This block will be excuted within
a barrier, i.e. all reads and writes are suspended for the duration of the block.
*/
#property (copy) TMMemoryCacheObjectBlock didAddObjectBlock;
I'm trying to make use of this to print a message when objects are added to the cache. My attempt so far:
[[_timedCache memoryCache] setDidAddObjectBlock:^{
NSLog(#"added something to cache");
}];
This gives a "parameter type mismatch" compiler error however. I'm fairly new to Objective-C and am probably doing something naive here. Any suggestions?

TMemoryCahceObjectBlock has the following signature: (TMMemoryCache *cache, NSString *key, id object), which your block doesn't have. Change the signature of your block and you are golden.

Related

In iOS #synchronized for 2 methods at once?

Typically #synchronized(self) creates something like critical section.
My problem is I have more than one function which should be accessed with one thread only.
But what will the application do if I write #synchronized(self) in each such method? Does it mean one thread can use method1 and other thread can use method2? If no then how to implement it correctly?
#synchronized attempts to obtain a lock on the object that is passed to it. If the lock is obtained then execution continues. If the lock can't be contained then the thread blocks until the lock can be obtained.
The object that you pass to #synchronized should be the object that you want to protect from simultaneous updates. This may be self or it may be a property of self. For example, consider the following simple queue implementation:
#property (nonatomic,strong) NSMutableArray *qArray;
-(void)append:(id)newObject {
#synchronized(self.qArray) {
[self.qArray addObject:newObject];
}
}
-(id) head {
id ret=nil;
#synchronized(self.qArray) {
if (self.qArray.count >0) {
ret=self.qArray[0];
[self.qArray removeObjectAtIndex:0];
}
}
return ret;
}
In this case self.qArray is a good choice for the #synchronized as it is the object being modified
Frome someone
The object passed to the #synchronized directive is a unique identifier used to distinguish the protected block. If you execute the preceding method in two different threads, passing a different object for the anObj parameter on each thread, each would take its lock and continue processing without being blocked by the other. If you pass the same object in both cases, however, one of the threads would acquire the lock first and the other would block until the first thread completed the critical section.
- (void)myMethod:(id)anObj
{
#synchronized(anObj)
{
// Everything between the braces is protected by the #synchronized directive.
}
}
If you access two (or more) functions via one thread. the #synchronized would don't affect your code. because your function is run synchronised without lock help.

ios about pass by reference

From my current understanding, the recommended way (with ARC enabled) of 'pass by reference' is like:
-(void)somefunc:(someclass **)byref;
// and 'someclass **' should be inferred to 'someclass * __autoreleasing *'
// am i right?
//or we could just explicitly define it like
-(void)somefunc:(someclass * __autoreleasing *)byref;
However, from the answer to this thread, Handling Pointer-to-Pointer Ownership Issues in ARC.
It seems -(void)somefunc:(someclass *__strong *)byref could do the trick as well (in demo2 of above link).
1.-(void)somefunc:(someclass * __autoreleasing *)byref;
2.-(void)somefunc:(someclass *__strong *)byref
For the first one, as documented by Apple it should be implicitly rewritten by compiler like this:
NSError * __strong error;
NSError * __autoreleasing tmp = error;
BOOL OK = [myObject performOperationWithError:&tmp];
error = tmp;
It seems the second one has a better performance? Because it omits the process of 'assign the value back' and 'autoreleasing'. But I rarely see functions declared like this. Is it a better way to use the second function to do the 'pass by reference' job?
Any suggestion or explanation? Thanks in advance.
the second function isnt thread-safe / 'delay safe'. the first one is more correct.
same reason as to why blocks capture params and performSelector retains the object.
imagine the caller fA allocs a strong reference to A and then calls an ASYNC function fB.
fA is done, fB not yet called.... so who retains A in the meantime?

iOS - Deal with Async task that point to a deallocated variable

I'm calling an asynchronous function from my controller and I pass to it a reference to an error variable, let's say:
NSError *err=nil;
[self myAsyncTask:&err];
if the controller get deallocated, the err variable does not exist anymore, so the app crash with a BAD_ACCESS error (because the function try to change the value of the err variable). How can I deal with that?
Notice that none of the built-in framework methods use pass by reference error reporting with asynchronous calls - they all use delegation or blocks to communicate error status. Using blocks, your API could be written to be used like:
[self doAsyncTaskWithErrorHandler: ^(NSError *error) {
//Handle error
}];
The method signature could look like
- (void)doAsyncTaskWithErrorHandler:(void (^)(NSError *error))errorHandler;
And in the implementation, where you used to do *error = someError; do something like:
NSError *error = ...;
if (errorHandler) {
errorHandler(error);
}
If I'm not mistaken this isn't really an issue with object lifetime though - if the stack frame is popped before the error is set then the pattern in the question would likely cause a crash as well.
How can I deal with that?
If you have an asynchronous function in process, you have to ensure that any variables that it uses remain valid until that function completes. Objective-C's memory management lends itself nicely to this -- a method like your -myAsyncTask can retain its arguments until it no longer needs them. That way, even if the controller (to use your word) is deallocated, the objects referred to by the variables will remain valid.
Another way to do it is to use a block for the async functionality. Blocks automatically retain the resources that they use, so they effectively solve this problem for you.

void(^)(NSData*) what does it mean?

Hi I am using this library and I found the function:
- (void) queueRequest:(NSString*)urlPath completion:(void(^)(NSData*))completionWithDownloadedData;
I try to pass a simple NSData *data; and it throw an error, what really mean (void(^)(NSData*))? Is the first time that I see it.
Thanks a lot.
(void(^)(NSData*)) declares a code block.
You can call your function this way.
[obj queueRequest:urlPath completion:^(NSData* data){
/* some code */
}];
data is a parameter to your block, which you can work with. The block will be called when the queueRequest will finish, asynchronously.
The interface is asynchronous, meaning that the data will only be available sometime later. This means that the method can’t simply return the NSData* (without blocking for all the time, which is impractical). The problem is nowadays often solved with blocks, and the completion argument here is a block that takes an NSData* argument and returns void. This is how you call such a method:
[foo queueRequest:path completion:^(NSData *receivedData) {
NSLog(#"Received data: %#", receivedData);
}];
The call will return immediately and the block will be executed sometime later, when the data is available.
It's a block that accepts a NSData object as it's only argument and returns nothing.
See Apple's Blocks Programming Topics.

Modifying mutable object in completion handler

I have a question about thread safety of the following code example from Apple (from GameKit programming guide)
This is to load achievements from game center and save it locally:
Step 1) Add a mutable dictionary property to your class that report achievements. This dictionary stores the collection of achievement objects.
#property(nonatomic, retain) NSMutableDictionary *achievementsDictionary;
Step 2) Initialize the achievements dictionary.
achievementsDictionary = [[NSMutableDictionary alloc] init];
Step 3) Modify your code that loads loads achievement data to add the achievement objects to the dictionary.
{
[GKAchievement loadAchievementsWithCompletionHandler:^(NSArray *achievements, NSError *error)
{
if (error == nil)
{
for (GKAchievement* achievement in achievements)
[achievementsDictionary setObject: achievement forKey: achievement.identifier];
}
}];
My question is as follows - achievementsDictionary object is being modified in the completion handler, without any locks of sort. Is this allowed because completion handlers are a block of work that will be guaranteed by iOS to be executed as unit on the main thread? And never run into thread safety issues?
In another Apple sample code (GKTapper), this part is handled differently:
#property (retain) NSMutableDictionary* earnedAchievementCache; // note this is atomic
Then in the handler:
[GKAchievement loadAchievementsWithCompletionHandler: ^(NSArray *scores, NSError *error)
{
if(error == NULL)
{
NSMutableDictionary* tempCache= [NSMutableDictionary dictionaryWithCapacity: [scores count]];
for (GKAchievement* score in scores)
{
[tempCache setObject: score forKey: score.identifier];
}
self.earnedAchievementCache= tempCache;
}
}];
So why the different style, and is one way more correct than the other?
Is this allowed because completion handlers are a block of work that will be guaranteed by iOS to be executed as unit on the main thread? And never run into thread safety issues?
This is definitely not the case here. The documentation for -loadAchievementsWithCompletionHandler: explicitly warns that the completion handler might be called on a thread other than the one you started the load from.
Apple's "Threading Programming Guide" classifies NSMutableDictionary among thread-unsafe classes, but qualifies this with, "In most cases, you can use these classes from any thread as long as you use them from only one thread at a time."
So, if both apps are designed such that nothing will be working with the achievement cache till the worker task has finished updating it, then no synchronization would be necessary. This is the only way in which I can see the first example as being safe, and it's a tenuous safety.
The latter example looks like it's relying on the atomic property support to make the switcheroo between the old cache and the new cache. This should be safe, provided all access to the property is via its accessors rather than direct ivar access. This is because the accessors are synchronized with respect to each other, so you do not risk seeing a half-set value. Also, the getter retains and autoreleases the returned value, so that code with the old version will be able to finish working with it without crashing because it was released in the middle of its work. A nonatomic getter simply returns the object directly, which means that it could be deallocated out from under your code if a new value were set for that property by another thread. Direct ivar access can run into the same problem.
I would say the latter example is both correct and elegant, though perhaps a bit over-subtle without a comment explaining how crucial the atomicity of the property is.

Resources