I am trying to remove and object from an mutable array - an array which is iterated through every frame (see tick: method).
I am getting
* Collection <__NSArrayM: 0xaa99cb0> was mutated while being enumerated.
exceptions.
So I added #synchronized() to lock it from being touched by other threads, but its still failing.
- (void)addEventSubscriber:(id <EventSubscriber>)eventSubscriber
{
[_eventSubscribers addObject:eventSubscriber];
}
- (void)removeEventSubscriber:(id <EventSubscriber>)eventSubscriber
{
#synchronized(_eventSubscribers) // Not working.
{
[_eventSubscribers removeObject:eventSubscriber];
}
}
- (void)tick:(ccTime)dt
{
for (id <EventSubscriber> subscriber in _eventSubscribers)
{
if ([subscriber respondsToSelector:#selector(tick:)])
{
[subscriber tick:dt];
}
}
}
You need to lock updates to the array completely while iterating. Adding synchronized blocks to both methods addEventSubscriber: and removeEventSubscriber: will not work because the array can change while being iterated over because the iteration is not synchronized. Simply put, only one of those three methods can run at a time.
You can use #synchronized, or an NSLock to manually lock array updates while it is being iterated over.
Alternatively, you could use GCD with a serial dispatch queue to ensure that only one method is executing at a time. Here's how that would work:
You could also store the queue as a property of the class object in which you're doing this processing.
// Create the queue
dispatch_queue_t myQueue = dispatch_queue_create("myQueue", NULL);
- (void)addEventSubscriber:(id <EventSubscriber>)eventSubscriber
{
dispatch_sync(myQueue, ^{
[_eventSubscribers addObject:eventSubscriber];
});
}
- (void)removeEventSubscriber:(id <EventSubscriber>)eventSubscriber
{
dispatch_sync(myQueue, ^{
[_eventSubscribers removeObject:eventSubscriber];
});
}
- (void)tick:(ccTime)dt
{
dispatch_sync(myQueue, ^{
for (id <EventSubscriber> subscriber in _eventSubscribers)
{
if ([subscriber respondsToSelector:#selector(tick:)])
{
[subscriber tick:dt];
}
}
});
}
You are only obtaining a lock while removing items from your array, not while enumerating items. The error suggests that within an enumeration you're trying to remove an item, which is allowed by your locking but not enumeration.
Simply locking the array before enumerating may not work either. The same thread can lock an object recursively, but if your enumeration and remove are on different threads then trying to remove within an enumeration would cause deadlock. If you are in this situation you'll need to rethink your model.
I run into this problem a lot. I have no experience with thread handling / synchronization beyond an undergraduate OS course, so this is what I came up with.
Every time you iterate over the list of objects and want to remove something - instead add that object to a global "objectsToRemove" array. In your update method, remove everything from the objectsToRemove, then clean up the array to avoid over-removing an object on the next update.
Cocos2D has a CCArray which is essentially an NSMutableArray with some added functionality– like being able to remove an item while iterating. I haven't read through the code myself, so I'm not sure how it is implemented and therefore I don't use it.
you need add synchronized in this functin too.
- (void)tick:(ccTime)dt
{
#synchronized(_eventSubscribers){
for (id <EventSubscriber> subscriber in _eventSubscribers)
{
if ([subscriber respondsToSelector:#selector(tick:)])
{
[subscriber tick:dt];
}
}
}
}
Related
I'm trying to build a Single Linked List using Parse PFObjects. Each PFObject has a pointer to the next object in the list. I can pin them locally, but I'm having an issue when saving them to Parse Server.
The problem start here:
+ (BFTask *)_deepSaveAsyncChildrenOfObject:(id)object withCurrentUser:(PFUser *)currentUser sessionToken:(NSString *)sessionToken;
// This saves all of the objects and files reachable from the given object.
// It does its work in multiple waves, saving as many as possible in each wave.
// If there's ever an error, it just gives up, sets error, and returns NO;
When trying to save the first object in the list, it will access the child (next object) and try to save that one first. As the child (next object) has also a pointer to the next object in list, this will keep happening until the last object in the list.
This succeeds for small amount of objects (<200) but once we are handling linked list with large amounts of objects, there is a crash in here:
/**
Finds all of the objects that are reachable from child, including child itself,
and adds them to the given mutable array. It traverses arrays and json objects.
#param node An kind object to search for children.
#param dirtyChildren The array to collect the result into.
#param seen The set of all objects that have already been seen.
#param seenNew The set of new objects that have already been seen since the
last existing object.
*/
+ (BOOL)collectDirtyChildren:(id)node
children:(NSMutableSet *)dirtyChildren
files:(NSMutableSet *)dirtyFiles
seen:(NSSet *)seen
seenNew:(NSSet *)seenNew
currentUser:(PFUser *)currentUser
error:(NSError * __autoreleasing *)error
This method is called by deepSaveAsyncChildrenOfObject to build a NSSet of the children objects that must be saved too.
#synchronized ([object lock]) {
// Check for cycles of new objects. Any such cycle means it will be
// impossible to save this collection of objects, so throw an exception.
if (object.objectId) {
seenNew = [NSSet set];
} else {
if ([seenNew containsObject:object] && error) {
*error = [PFErrorUtilities errorWithCode:kPFErrorInvalidPointer
message:#"Found a circular dependency when saving."];
return NO;
}
// 🚨CRASH: Thread 160: EXC_BAD_ACCESS (code=2, address=0x70000fc80f38)
seenNew = [seenNew setByAddingObject:object];
}
// Check for cycles of any object. If this occurs, then there's no
// problem, but we shouldn't recurse any deeper, because it would be
// an infinite recursion.
if ([seen containsObject:object]) {
return YES;
}
seen = [seen setByAddingObject:object];
// Recurse into this object's children looking for dirty children.
// We only need to look at the child object's current estimated data,
// because that's the only data that might need to be saved now.
toSearch = [object._estimatedData.dictionaryRepresentation copy];
}
So, this could be avoided by saving the PFObjects without saving its children, is there any way to do this? Or is there any workaround to save linked lists to Parse Server, maybe by using Cloud Code, or modifying the data model?
I'm using PromiseKit to simply my API requests.
In this scenario, I'm fetching a list of objects IDs from the server. I need to then fetch details for each ID, and return an array of details. Fairly common scenario.
Effectively, I need to add promises to the promise chain from within a FOR loop which is contained in the FIRST promise.
I've created code that begins to drift right, but the chain completes before the second chain of promises (fill shallow model requests) can be executed.
[PMKPromise promiseWithResolver:^(PMKResolver resolve) {
// Fetch an array of object IDs (shallow objects)
[APIManager fetchObjectListWithCompletion:^(NSArray *resultObjects, NSError *error) {
resolve(error ?: resultObjects[0]);
}];
}].then(^(NSArray *objects){
// Fill each shallow object (query details)
PMKPromise *fetches = [PMKPromise promiseWithValue:nil];
for(id model in objects) {
fetches.then(^{
[APIManager fillShallowObject:model withCompletion:^(NSArray *resultObjects, NSError *error) {
// resolve?
}];
});
}
// Return promise that contains all fill requests
return fetches;
})].then(^{
// This should be executed after all fill requests complete
// Instead it's executed after the initial ID array request
});
Is there a better way to do what I'm trying to accomplish? Perhaps a way to append a promise (.then) with a resolver?
I think you want when:
[AnyPromise promiseWithAdapterBlock:^(id adapter) {
[APIManager fetchObjectListWithCompletion:adapter];
}].then(^(id objects){
NSMutableArray *promises = [NSMutableArray new];
for (id model in objects) {
id promise = [AnyPromise promiseWithAdapterBlock:^(id adapter){
[APIManager fillShallowObject:model withCompletion:adapter];
}];
[promises addObject:promise];
}
return PMKWhen(promises);
}).then(^(NSArray *results){
// when waits on all promises
});
Code is PromiseKit 3.
I have a thread-safe class, a cancel token, that transitions from an unstable mutable state (not cancelled) to a stable immutable state (cancelled). Once an instance has become immutable, I'd like to stop paying the cost of acquiring a lock before checking the state.
Here's a simplification of what things look like now:
-(bool) isCancelled {
#synchronized(self) {
return _isCancelled;
}
}
-(bool) tryCancel {
#synchronized(self) {
if (_isCancelled) return false;
_isCancelled = true;
}
return true;
}
and what I want to try:
-(bool) isCancelled {
bool result;
// is the following correct?
// can the two full barriers be reduced to a single read-acquire barrier somehow?
OSMemoryBarrier();
result = _isCancelled != 0;
OSMemoryBarrier();
return result;
}
-(bool) tryCancel {
return OSAtomicCompareAndSwap32Barrier(0, 1, &_isCancelled);
}
Is using two memory barriers the correct approach? How should I expect it to compare to the cost of acquiring a lock (insert standard refrain about profiling here)? Is there a cheaper way to do it?
Edit: this sounds like possible premature optimization. is this lock acquisition slowing things down?
Edit2: its possible compiler optimization will defeat this. be aware.
if you are concerned about the gotchas with double checked locking, perhaps dispatch_once() could be useful for you?
would double checked locking work in this case?
-(void) doSomething {
if (!_isCanceled) { //only attempt to acquire lock if not canceled already
#synchronized(self) {
if (!_isCanceled) // now check again (the double check part)
doSomethingElse();
}
}
}
read the wikipedia entry on double checked locking for more info
The client I'm building is using Reactive Cocoa with Octokit and so far it has been going very well. However now I'm at a point where I want to fetch a collection of repositories and am having trouble wrapping my head around doing this the "RAC way"
// fire this when an authenticated client is set
[[RACAbleWithStart([GHDataStore sharedStore], client)
filter:^BOOL (OCTClient *client) {
return client != nil && client.authenticated;
}]
subscribeNext:^(OCTClient *client) {
[[[client fetchUserRepositories] deliverOn:RACScheduler.mainThreadScheduler]
subscribeNext:^(OCTRepository *fetchedRepo) {
NSLog(#" Received new repo: %#",fetchedRepo.name);
}
error:^(NSError *error) {
NSLog(#"Error fetching repos: %#",error.localizedDescription);
}];
} completed:^{
NSLog(#"Completed fetching repos");
}];
I originally assumed that -subscribeNext: would pass an NSArray, but now understand that it sends the message every "next" object returned, which in this case is an OCTRepository.
Now I could do something like this:
NSMutableArray *repos = [NSMutableArray array];
// most of that code above
subscribeNext:^(OCTRepository *fetchedRepo) {
[repos addObject:fetchedRepo];
}
// the rest of the code above
Sure, this works, but it doesn't seem to follow the functional principles that RAC enables. I'm really trying to stick to conventions here. Any light on capabilities of RAC/Octokit are greatly appreciated!
It largely depends on what you want to do with the repositories afterward. It seems like you want to do something once you have all the repositories, so I'll set up an example that does that.
// Watch for the client to change
RAC(self.repositories) = [[[[[RACAbleWithStart([GHDataStore sharedStore], client)
// Ignore clients that aren't authenticated
filter:^ BOOL (OCTClient *client) {
return client != nil && client.authenticated;
}]
// For each client, execute the block. Returns a signal that sends a signal
// to fetch the user repositories whenever a new client comes in. A signal of
// of signals is often used to do some work in response to some other work.
// Often times, you'd want to use `-flattenMap:`, but we're using `-map:` with
// `-switchToLatest` so the resultant signal will only send repositories for
// the most recent client.
map:^(OCTClient *client) {
// -collect will send a single value--an NSArray with all of the values
// that were send on the original signal.
return [[client fetchUserRepositories] collect];
}]
// Switch to the latest signal that was returned from the map block.
switchToLatest]
// Execute a block when an error occurs, but don't alter the values sent on
// the original signal.
doError:^(NSError *error) {
NSLog(#"Error fetching repos: %#",error.localizedDescription);
}]
deliverOn:RACScheduler.mainThreadScheduler];
Now self.repositories will change (and fire a KVO notification) whenever the repositories are updated from the client.
A couple things to note about this:
It's best to avoid subscribeNext: whenever possible. Using it steps outside of the functional paradigm (as do doNext: and doError:, but they're also helpful tools at times). In general, you want to think about how you can transform the signal into something that does what you want.
If you want to chain one or more pieces of work together, you often want to use flattenMap:. More generally, you want to start thinking about signals of signals--signals that send other signals that represent the other work.
You often want to wait as long as possible to move work back to the main thread.
When thinking through a problem, it's sometimes valuable to start by writing out each individual signal to think about a) what you have, b) what you want, and c) how to get from one to the other.
EDIT: Updated to address #JustinSpahrSummers' comment below.
There is a -collect operator that should do exactly what you're looking for.
// Collect all receiver's `next`s into a NSArray. nil values will be converted
// to NSNull.
//
// This corresponds to the `ToArray` method in Rx.
//
// Returns a signal which sends a single NSArray when the receiver completes
// successfully.
- (RACSignal *)collect;
In NHibernate 3.1, ISession.SaveOrUpdateCopy() has been marked as deprecated. The documentation suggests using Merge() instead. The documentation for each is as follows:
SaveOrUpdateCopy(object obj)
Copy the state of the given object onto the persistent object with the same identifier. If there is no persistent instance currently associated with
the session, it will be loaded. Return the persistent instance. If the
given instance is unsaved or does not exist in the database, save it and
return it as a newly persistent instance. Otherwise, the given instance
does not become associated with the session.
Merge(object obj)
Copy the state of the given object onto the persistent object with the same
identifier. If there is no persistent instance currently associated with
the session, it will be loaded. Return the persistent instance. If the
given instance is unsaved, save a copy of and return it as a newly persistent
instance. The given instance does not become associated with the session.
This operation cascades to associated instances if the association is mapped
with cascade="merge".
The semantics of this method are defined by JSR-220.
They look nearly identical to me, but there are bound to be some subtleties involved. If so, what are they?
SaveOrUpdateCopy is now considered obsolete and thus Merge is meant to take over for it (hence its extreme similarity).
They are pretty much the same except I don't think those cascade options were available with SaveOrUpdateCopy. However, that point is moot as Merge should be method you use.
UPDATE: I went in to the source code of NHibernate just to make sure they are as similar as I was thinking and here is what I found.
Both Merge and SaveOrUpdateCopy have very similar implementations:
public object Merge(string entityName, object obj)
{
using (new SessionIdLoggingContext(SessionId))
{
return FireMerge(new MergeEvent(entityName, obj, this));
}
}
public object SaveOrUpdateCopy(object obj)
{
using (new SessionIdLoggingContext(SessionId))
{
return FireSaveOrUpdateCopy(new MergeEvent(null, obj, this));
}
}
Their FireXXXX methods are also very similar:
private object FireMerge(MergeEvent #event)
{
using (new SessionIdLoggingContext(SessionId))
{
CheckAndUpdateSessionStatus();
IMergeEventListener[] mergeEventListener = listeners.MergeEventListeners;
for (int i = 0; i < mergeEventListener.Length; i++)
{
mergeEventListener[i].OnMerge(#event);
}
return #event.Result;
}
}
private object FireSaveOrUpdateCopy(MergeEvent #event)
{
using (new SessionIdLoggingContext(SessionId))
{
CheckAndUpdateSessionStatus();
IMergeEventListener[] saveOrUpdateCopyEventListener = listeners.SaveOrUpdateCopyEventListeners;
for (int i = 0; i < saveOrUpdateCopyEventListener.Length; i++)
{
saveOrUpdateCopyEventListener[i].OnMerge(#event);
}
return #event.Result;
}
}
The methods are exactly the same except they draw on different event listener lists, but even the types of the lists (IMergeEventListener) are the same!
Looking at the listener lists, they are both initialized with a default listener. The default listener for the Merge listen handlers is of type DefaultMergeEventListener while the SaveOrUpdateCopy is DefaultSaveOrUpdateCopyEventListener. Thus, the difference between them is just the difference in these two implementations (that is if you keep the default listener, which is 99% of the time).
However, the real interesting fact IS the difference in implementation. If you look at DefaultSaveOrUpdateCopyEventListener you get this:
public class DefaultSaveOrUpdateCopyEventListener : DefaultMergeEventListener
{
protected override CascadingAction CascadeAction
{
get { return CascadingAction.SaveUpdateCopy; }
}
}
This means the default behavior for Merge and SaveOrUpdateCopy only differs in the cascading actions, everything else is exactly the same.