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?
Related
I have a Realm object (LFEMemory) which has a publish method.
When I call the publish method, I have to upload an image to AWS and then update the object with the URL returned by Amazon.
The problem is that when the block returns from AWS, my self LFEMemory object is no longer thread-safe. (In fact, it usually is during the usual running of the app but never if I'm using an App Extension).
I could fix this by removing the publish method from the realm object, and handling it in a controller object, which can fetch a new realm object on the new thread. But that means I need to create new realms everytime I call a block, which surely isn't a good practise.
How do most people handle this situation?
- (void)publishWithBlock:(ResultBlock)block {
FileUploadManager *manager = [[FileUploadManager alloc] init];
[manager uploadWithSuccess:^(NSString *filename) {
//self is no longer thread-safe and will cause a crash
self.media.path = filename;
} failure:^(NSError *error) {
block(NO, error);
};
}
You have various options you can explore:
1) if your object has a primary key (string or a number) you can store the id as a constant inside the method and use it to fetch back the object from any thread by using [Realm objectOfType:forPrimaryKey:]. docs
Don't be afraid to get a new realm from the different thread if that's what you need to do - that does not create "another" Realm or duplicate your file.
2) if you don't have a primary key you can simply create self.media on the main thread and whenever the upload has finished, switch again to the main queue and modify your object there - modifying a property or two on a Realm object will not harm at all your performance on the main thread.
Further - if you have access to your object (as in self.media) it already gives you access to the original Realm used to create / read the object via its realm property docs
Still - I'd go with using the primary key of the object to re-fetch a reference to the object I need if in doubt.
I have a setup with a main model (QStandardModel), a proxy model which changes the output of the DisplayRole, and a separate tableview displaying each model. Inside the main model data is a user role that stores a pointer to another QObject which is used by the proxy model to get the desired display value.
I'm running into problems when the object pointed to by that variable is deleted. I am handling deletion in the main model via the destroyed(QObject*) signal. Inside the slot, I search through the model looking for any items that are pointing to the object and delete the reference.
That part works fine on its own but I also have connected to the onDataChanged(...) signal of the proxy model, where I call resizeColumnsToContents() on the proxy model. This then calls the proxy's data() function. Here I check to see if the item has a pointer and, if it does, get some information from the object for display.
The result of all this becomes:
Object about to be deleted triggers destroyed(...) signal
Main model looks for any items using the deleted object and calls setData to remove the reference
Tableview catches onDataChanged signal for the proxy model and resizes columns
Proxy model's data(...) is called. It checks if the item in the main model has the object pointer and, if so, displays a value from the object. If not, it displays something else.
The problem is, at step 4 the item from the main model apparently still hasn't been deleted; the pointer address is still stored. The object the pointer was referencing, though, has been deleted by this point resulting in a segfault.
How can I fix my setup to make sure the main model is finished deleting pointer references before the proxy model tries to update?
Also, here is pseudo-code for the relevant sections:
// elsewhere
Object *someObject = new QObject();
QModelIndex index = mainModel->index(0,0);
mainModel->setData(index, someObject, ObjectPtrRole);
// do stuff
delete someObject; // Qt is actually doing this, I'm not doing it explicitly
// MainModel
void MainModel::onObjectDestroyed(QObject *obj)
{
// iterating over all model items
// if item has pointer to obj
item->setData(QVariant::fromValue(NULL), ObjectPtrRole));
}
// receives onDataChanged signal
void onProxyModelDataChanged(...)
{
ui->tblProxyView->reseizeColumnsToContents();
}
void ProxyModel::data(const QModelIndex &index, int role) const
{
QModelIndex srcIndex = mapToSource(index);
if(role == Qt::DisplayRole)
{
QVariant v = sourceModel()->data(srcIndex, ObjectPtrRole);
Object *ptr = qvariant_cast<Object*>(v);
if(ptr != NULL)
return ptr->getDisplayData();
else
return sourceModel->data(srcIndex, role);
}
}
The problem is ptr is not NULL, but the referenced object is deleted, at the time ProxyModel::data(...) is called so I end up with a segfault.
To avoid dangling pointer dereferences with instances of QObject, you can do one of two things:
Use object->deleteLater - the object will be deleted once the control returns to the event loop. Such functionality is also known as autorelease pools.
Use a QPointer. It will set itself to null upon deletion of the object, so you can check it before use.
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;
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];
}
}
}
}
I am learning algorithms and data structures and to train I am trying to design and implement a binary tree using objective-c.
So far I have the following Classes:
main - for testing
Node - node of tree
BinaryTree - for all methods related to the tree
One of the first methods in BinaryTree class I implemented is insertNode:forRoot:.
- (void)insertNodeByRef:(Node **)node forRoot:(Node **)root{
if (head == NULL) {
head = *node;
}
// Case 2 root is null so can assign the value of the node to it
if (root == NULL) {
root = node;
} else {
if (node.data > root.data) { // to the right
[self insertNode:node forRoot:root.right];
} else if (node.data < root.data) { //or to the left
[self insertNode:node forRoot:root.left];
}
}
}
Where the interface of Node class looks like:
#interface Node : NSObject
#property(nonatomic, assign) int data;
#property(nonatomic, strong) Node * right;
#property(nonatomic, strong) Node * left;
#end
My problem is that I don't know how to access the Node class member variables if I am passing Node as a reference. Whenever I try to access the node properties (like data, left or right) I am getting the following error message:
Member reference base type 'Node *__autoreleasing *' is not a structure or union
So my questions is:
how can I access those properties (data, left or right) and use them to store either int data or reference to another Node?
Hope it makes sense. Thanks!
Your code is mixing two common approaches to the task, hence the problem. You are also using an abstract data type (ADT) type approach, rather than an object-oriented one, so there are three approaches to consider.
In both ADT approaches your tree is represented by a reference to its root, in Objective-C this is probably stored in an instance variable:
Node *TreeRoot;
Note also that both of these algorithms use field references, a->b, rather than property references, a.b - this is because the former references a variable and the second algorithm requires passing a reference to a variable.
Functional ADT: Pass-by-value and assign result
In this approach a node is inserted into a tree and a modified tree is returned which is assigned back, e.g. the top-level call to insert a Node nodeToInsert would be:
TreeRoot = insertNode(nodeToInsert, TreeRoot);
and the insertNode function looks like:
Node *insertNode(Node *node, Node *root)
{
if(root == nil)
{ // empty tree - return the insert node
return node;
}
else
{ // non-empty tree, insert into left or right subtree
if(node->data > root->data) // to the right
{
root->right = insertNode(node, root->right);
}
else if(node->data < root->data)//or to the left
{
root->left = insertNode(node, root->left);
}
// tree modified if needed, return the root
return root;
}
}
Note that in this approach in the case of a non-empty (sub)tree the algorithm performs a redundant assignment into a variable - the assigned value is what is already in the variable... Because of this some people prefer:
Procedural ADT: Pass-by-reference
In this approach the variable holding the root of the (sub)tree is passed-by-reference, rather than its value being passed, and is modified by the called procedure as needed. E.g. the top-level call would be:
insertNode(nodeToInsert, &TreeRoot); // & -> pass the variable, not its value
and the insertNode procedure looks like:
void insertNode(Node *node, Node **root)
{
if(*root == nil)
{ // empty tree - insert node
*root = node;
}
else
{ // non-empty tree, insert into left or right subtree
Node *rootNode = *root;
if(node->data > rootNode->data) // to the right
{
insertNode(node, &rootNode->right);
}
else if(node->data < rootNode->data)//or to the left
{
insertNode(node, &root->left);
}
}
}
You can now see that your method is a mixture of the above two approaches. Both are valid, but as you are using Objective-C it might be better to take the third approach:
Object-Oriented ADT
This is a variation of the procedural ADT - rather than pass a variable to a procedure the variable, now called an object, owns a method which updates itself. Doing it this way means you must test for an empty (sub)tree before you make a call to insert a node, while the previous two approaches test in the call. So now we have the method in Node:
- (void) insert:(Node *)node
{
if(node.data > self.data) // using properties, could also use fields ->
{
if(self.right != nil)
[self.right insert:node];
else
self.right = node;
}
else if(node.data < rootNode.data)
{
if(self.left != nil)
[self.left insert:node];
else
self.left = node;
}
}
You also need to change the top level call to do the same test for an empty tree:
if(TreeRoot != nil)
[TreeRoot insert:nodeToInsert];
else
TreeRoot = nodeToInsert;
And a final note - if you are using MRC, rather than ARC or GC, for memory management you'll need to insert the appropriate retain/release calls.
Hope that helps you sort things out.
First of all, don't write your methods to take Node **. It's just confusing.
Second, think about how it should work. Describe to yourself how it should work at a pretty abstract level. Translate that description directly into code, inventing new (not-yet-written!) messages where necessary. If there are steps you don't know how to do yet, just punt those off to new messages you'll write later. I'll walk you through it.
Presumably you want the public API of BinaryTree to include this message:
#interface BinaryTree
- (void)insertValue:(int)value;
So how do you implement insertValue:? Pretend you're the BinaryTree object. What's your high-level description of what you need to do to insert a value? You want to create a new Node. Then you want to insert that new Node into yourself. Translate that description directly into code:
#implementation BinaryTree {
Node *root_; // root node, or nil for an empty tree
}
- (void)insertValue:(int)value {
Node *node = [[Node alloc] initWithData:value];
[self insertNode:node];
}
Now think about how you do the inserting. Well, if you are an empty tree, your root_ is nil and you can just set it to the new node. Otherwise, you can just ask your root node to insert the new node under himself. Translate that description directly into code:
- (void)insertNode:(Node *)node {
if (root_ == nil) {
root_ = node;
} else {
[root_ insertNode:node];
}
}
Now pretend you're a Node. You've been asked to insert a new Node under yourself. How do you do it? You have to compare the new node's value to your value. If the new node's value is less than your value, you want to insert the new node on your left side. Otherwise, you want to insert it on your right side. Translate that description directly into code:
#implementation Node
- (void)insertNode:(Node *)node {
if (node.data < self.data) {
[self insertNodeOnLeftSide:node];
} else {
[self insertNodeOnRightSide:node];
}
}
Now you're still a Node, and you've been asked to insert a new node on your left side. How do you do it? Well, if you don't have a child on your left side yet, just use the new node as your left child. Otherwise, you ask your left child to insert the new node under himself. Translate that description directly into code:
- (void)insertNodeOnLeftSide:(Node *)node {
if (self.left == nil) {
self.left = node;
} else {
[self.left insertNode:node];
}
}
I'll leave the implementation of insertNodeOnRightSide: as an exercise for the reader. ;^)
Your code, in my opinion, has a lot of logic errors. Maybe consider reviewing what a pointer-to-pointer is to insure you're designing the desired effect. Likewise, you need to dereference node/root to access them in normal state. Otherwise, the error is valid, Node** is not type of structure or union.
(Node **)node is a pointer to an object pointer so node.something is invalid because you are a reference to far away from the object.
But (*node).something will work.
Addition for comments :
When you originally call this method : -(void)insertNodeByRef:(Node **)node forRoot:(Node **)root how do you call it?
From the error you've post in your comment it look to me that you are doing :
Node *n = [[Node alloc] init];
[aNode insertNodeByRef:n forRoot:aRoot];
when your method signature state that you need to call it like this :
[aNode insertNodeByRef:&n forRoot:&aRoot];
To pass the address of the pointer to the object.
I'm saying this because your error is now stating that your are sending Node * instead of Node ** which are 2 different thing. (( Incompatible pointer types sending 'Node *' to parameter of type 'Node **' ) I've remove the __autoreleasing between the 2 *, it was obscuring the error message.)
So in other word you are passing a pointer to an object when your method is asking for a pointer TO A pointer to an object.