UIColor foo = (UIColor) bar.Copy();
foo.Dispose();
I am observing that the above code causes bar to also be disposed. Based on the documentation, foo should be a new instance of bar and therefore I would expect that bar would not be affected by any changes made to foo.
Can someone explain why this is happening? Perhaps I'm misunderstanding something... If so, is there another way to get a copy of a UIColor without having to copy over all of the property values myself?
Related
I'm trying to use some of the new diffing classes built into iOS 13 along with Core Data. The problem I am running into is that controllerdidChangeContentWith doesn't work as expected. It passes me a snapshot reference, which is a reference to a
NSDiffableDataSourceSnapshot<Section, NSManagedObjectID>
meaning I get a list of sections/Object ID's that have changed.
This part works wonderfully. But the problem comes when you get to the diffing in the collection view. In the WWDC video they happily call
dataSource.apply(snapshot, animatingDifferences: true)
and everything works magically, but that is not the case in the actual API.
In my initial attempt, I tried this:
resolvedSnapshot.appendItems(snapshot.itemIdentifiersInSection(withIdentifier: section).map {
controller.managedObjectContext.object(with: $0 as! NSManagedObjectID) as! Activity
}, toSection: .all)
And this works for populating the cells, but if data is changed on a cell (IE. the cell title) the specific cell is never reloaded. I took a look at the snapshot and it appears the issue is simply that I have references to these activity objects, so they are both getting updated simultaneously (Meaning the activity in the old snapshot is equivalent to the one in the new snapshot, so the hashes are equal.)
My current solution is using a struct that contains all my Activity class variables, but that disconnects it from CoreData. So my data source became:
var dataSource: UICollectionViewDiffableDataSource<Section, ActivityStruct>
That way the snapshot actually gets two different values, because it has two different objects to compare. This works, but it seems far from elegant, is this how we were meant to use this? Or is it just in a broken state right now? The WWDC video seems to imply it shouldn't require all this extra boilerplate.
I ran into the same issue and I think I figured out what works:
There are two classes: UICollectionViewDiffableDataSource and UICollectionViewDiffableDataSourceReference
From what I can tell, when you use the first, you're taking ownership as the "Source of Truth" so you create an object that acts as the data source. When you use the second (the data source reference), you defer the "Source of Truth" to another data source (in this case, CoreData).
You would instantiate a ...DataSourceReference essentially the same way as a ...DataSource:
dataSourceReference = UICollectionViewDiffableDataSourceReference(collectionView: collectionView, cellProvider: { (collectionView, indexPath, object) -> UICollectionViewCell? in
let identifier = <#cell identifier#>
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: identifier, for: indexPath)
<#cell configuration#>
return cell
})
And then later when you implement the NSFetchedResultsControllerDelegate, you can use the following method:
func controller(_ controller: NSFetchedResultsController<NSFetchRequestResult>, didChangeContentWith snapshot: NSDiffableDataSourceSnapshotReference)
{
dataSourceReference.applySnapshot(snapshot, animatingDifferences: true)
}
I watched the WWDC video as well and didn't see this referenced. Had to make a few mistakes to get here. I hope it works for you!
Suppose I define "Class original:" and create a class attribute "one = 4." Then I create an instance of the class "First = original()." My understanding is that First now contains a pointer to original and "First.one" will return "4." However, suppose I create "Second = original()" and then set "Second.one = 5." What exactly happens in memory? Does a new copy of Class original get created with a class attribute of 5?
I've created a Class original with class attribute one. I then created two instances of this class (First and Second) and verified that id(First.one) and id(Second.one) are pointing to the same place. They both return the same address. However, when I created Third=original() and set Third.one = 5 and then check id(Thrid.one) it appears to be pointing somewhere else. Where is it pointing and what happened? When I check original.one it still returns "4" so obviously the original object is not being modified. Thanks.
It appears you are asking about a piece of code similar to this:
class Original:
def __init__(self, n):
self.one = n
first = Original(4)
second = Original(4)
third = Original(5)
print(id(first.one))
# 140570468047360
print(id(second.one))
# 140570468047360
print(id(third.one))
# 140570468047336
Suppose I define "Class original:" and create a class attribute "one = 4." Then I create an instance of the class "First = original()." My understanding is that First now contains a pointer to original
No. The variable references the instance you created, not the class. If it referenced the class, there would be no way for you to get at the instance you just created.
The instance will, somewhere in its object header, of course contain a pointer to its class. Without that pointer, method lookup wouldn't be possible, since you wouldn't be able to find the class from the instance.
and "First.one" will return "4."
Yes. The attribute one of first contains a pointer to the object 4 (which is an instance of the class int).
[Note that technically, some Python implementations will perform an optimization and actually store the object 4 directly in the attribute instead of a pointer to the object. But that is an internal implementation detail.]
However, suppose I create "Second = original()" and then set "Second.one = 5." What exactly happens in memory? Does a new copy of Class original get created with a class attribute of 5?
No. Why would you need a separate copy of the class? The methods are still the same for both instances. In fact, that is precisely the reason why methods in Python take the instance as their first argument! That way, there need only be one method. (This is actually the same in every OO language, except that in most other languages, this argument is "invisible" and only accessible using a special keyword like self in Ruby, Smalltalk, Self, and Newspeak or this in Java, C#, and Scala.)
I've created a Class original with class attribute one. I then created two instances of this class (First and Second) and verified that id(First.one) and id(Second.one) are pointing to the same place. They both return the same address. However, when I created Third=original() and set Third.one = 5 and then check id(Thrid.one) it appears to be pointing somewhere else.
It is not quite clear to me what your question is here. first.one and second.one both point to 4, so they both point to the same ID since they both point to the same object. third.one points to 5, which is obviously a different object from 4, so naturally, it has a different ID.
It is, in fact, one of the requirement of IDs that different objects that exist at the same time must have different IDs.
Where is it pointing and what happened?
Again, it is not quite clear what you are asking.
It is pointing at 5, and nothing happened.
When I check original.one it still returns "4" so obviously the original object is not being modified.
Indeed, it isn't. Why would it be?
I have a hierarchy of managed object contexts, like so:
A
/ \
B C
...where A's parent is the persistent store. A and C use a private queue, and B uses the main queue. I've found that doesn't seem to matter, but I'll note it anyway.
So, here is the best way to replicate the issue:
- Context B creates an object. Because I need to reference this same object multiple places, I obtain a permanent object ID via obtainPermanentIDsForObjects. I then save.
- Context A inherits the change, saves it out to the permanent store. Context C sees the change notification and merges the changes in. All is good so far.
- I grab the object from context C and change one of the properties. I then save. Context A inherits the change and saves it to disk.
This is where it gets weird. Context B never sees the change. There is a change notification I intercept like so:
-(void)contextDidSaveNotification:(NSNotification *)notification
{
NSManagedObjectContext *context = [notification object];
if(context!=_moc.parentContext)
return;
NSLog(#"Context %# did save, merging into %#, info:\n%#", context, _moc, [notification userInfo]);
[_moc mergeChangesFromContextDidSaveNotification:notification];
}
And I see the change go out, and seeing it merged in to context B. But the object I created in the first step never sees any changes.
I've traced this all back to one very specific thing. If I don't obtain a permanent object ID on the object in the very first step, the changes get merged back to the original object in context B just fine. But this leaves me without a reliable object ID to use in other contexts (as far as I know).
This seems like it could be a bug. I hope not. But for some reason when I obtain a permanent object ID it blocks changes from being merged back in from other contexts.
Has anyone else seen this behavior? Any solutions?
(I know changes from context C are making it in to A, and A is saving them to disk. If I relaunch the app the changes are there from disk.)
this is the source of the issue. My answer there was deleted with the hint to start a new question. So, here we go:
I want to pass the managed reference of this to unmanaged code. And then call the managed callback out of the unmanaged callback.
public ref class CReader
with a private field
private:
[...]
void *m_pTag;
[...]
In the constructor of the managed class I initialize the m_pTag like this:
m_pTag = new gcroot<CReader ^>(this);
Later, I pass this void *m_pTag to the unmanaged code. If the unmanaged callback is called, I'm casting the void *m_pTag back to managed reference and call the managed callback
(*(gcroot<CReader ^>*)pTag)->MANAGEDCALLBACKFUNCTION
and there is an exception thrown, if the DLL is used under another AppDomain. The Debugger stops in gcroot.h on line
// don't return T& here because & to gc pointer not yet implemented
// (T should be a pointer anyway).
T operator->() const {
// gcroot is typesafe, so use static_cast
return static_cast<T>(__VOIDPTR_TO_GCHANDLE(_handle).Target);
}
with Cannot pass a GCHandle across AppDomains.
My question is, what should I do?
Sincerly,
Sebastian
==================== EDIT ====================
I am now able to reproduce the problem. I've took some screenshots, to show the issue.
1st screenshot: constructor
snd screenshot: callback
The problem is, that the value-member of the struct gcroot in the callback is empty.
Thank you.
Sebastian
==================== EDIT ====================
Push.
The gcroot<> C++ class is a wrapper that uses the GCHandle class. The constructor calls GCHandle.ToIntPtr() to turn the handle into an opaque pointer, one that you can safely store as a member of an unmanaged struct or C++ class.
The cast then, later, converts that raw pointer back to the handle with the GCHandle.FromIntPtr() method. The GCHandle.Target property gives you the managed object reference back.
GCHandle.FromIntPtr() can indeed fail, the generic exception message is "Cannot pass a GCHandle across AppDomains". This message only fingers the common reason that this fails, it assumes that GCHandle is used in safe code and simply used incorrectly.
The message does not cover the most common reason that this fails in unsafe code. Code that invariably dies with undiagnosable exceptions due to heap corruption. In other words, the gcroot<> member of the C++ class or struct getting overwritten with an arbitrary value. Which of course dooms GCHandle.FromIntPtr(), the CLR can no longer find the handle back from a junk pointer value.
You diagnose this bug the way you diagnose any heap corruption problem. You first make sure that you get a good repro so you can trip the exception reliably. And you set a data breakpoint on the gcroot member. The debugger automatically breaks when the member is written inappropriately, the call stack gives you good idea why this happened.
I have set up a class that conforms to NSCoding, and works as expected when I first create the object. It is essentially the same set up as this
The problem I am having is that the properties of the object when changed are not kept.
For example,
Foo is created and has a property called name.
Foo.name = #"bar"
I can encode / decode the object and it retains the name bar.
If I try and change
Foo.name = #"newName"
The encode method is not called again, so foo.name remains as #"bar"
(I have a log state within the encode method)
Also,
I am using a core data object, that has a transformable property which points to the foo object.
Thanks
To "save" the object, you have to call the encode method, e.g. to write it to disk or send it to an output stream.
However, since you are using Core Data to persist the object, you have to call
[managedObjectContext save:&error];
to persist the object after changing it.
That being said, I do not think it makes a lot of sense to have a transformable property that points to a custom class that keeps a string property. Instead, you should think of a more appropriate data structure so you only need transformable properties for non standard data types that cannot be persisted by using the standard data types already built into Core Data.