Calling NSManagedObject function breaks but not when accessing a variable - multithreading

So I have an NSManagedObject called Student. There is a part of my code that sometimes breaks when I call a method on a Student object e.g student.performTask(). This gives me a EXC_BAD_ACESS which makes me believe it is a threading core data issue. However, one line before where the code breaks I access a variable from the object and there is no runtime error. So my question is: what is the difference between making a call to a variable in an NSManagedObject vs calling a method? What causes it to break for one but not for the other?
Note: the program breaks before executing a single line in the method.
Here is a snippet of my code:
let attendances = Attendance.createOrUpdateFromJsonDictionary(data!)
var seenIds = [NSNumber]()
for attendance in attendances {
let student = attendance.student
if !seenIds.contains(student.id) { //does not complain when accessing the id
seenIds.append(student.id)
let oldCurrent = student.isCurrent //does not complain or break here
student.setIsCurrent() //<- breaks here
Could the fact that attendance is also a NSManagedObject that has student as a relationship and I am grabbing student from attendance?

If this is being called within another thread then you are violating the thread confinement rules of Core Data.
I highly suggest reading the concurrency section of the Core Data Programming Guide (recently updated) and apply the recommendations therein.
If you want to operate in the completion block of a third part networking library then you will need to call -performBlock: or -performBlockAndWait: against the context and only access the NSManagedObject instances within that block. Otherwise you will get unexpected and inconsistent results.

Related

Best practice core data same view for creating and editing [duplicate]

This question already has answers here:
swiftui how to fetch core data values from Detail to Edit views
(2 answers)
Closed 11 months ago.
I try to use core data to store persistent data on an iOS device. I've got user flows to create and edit domain objects with a few related and deeply nested objects.
Those user flows are very similar, so I would like to use the same views for those tasks, just deciding on appear if the view got an existing domain object passed or it needs to create a new one.
After testing different approaches, nothing seems to fit this context so I wonder if there are recommended ways for this situation?
The following options got tested:
initializing the core data object in init() results in an Modifying state during view update, this will cause undefined behavior. warning
initializing the core data object in .onAppear requires the #ObservedObject var domainObjectPassed: DomainObject to be optional, not quite what I'm looking for as well
Any suggestions?
Already did that. I extracted the same logic into one view and have two distinct wrapper views that should handle this problem. But I've got the same situation one level higher.
struct CreateView: View {
#ObservedObject private var domainObject: DomainObject
init(moc: NSManagedObjectContext) {
domainObject = DomainObject(context: moc)
domainObject.id = UUID()
try? moc.save()
}
var body: some View {
CustomizeView(domainObject: domainObject)
}
}
-> results in warning from the first option
struct CreateView: View {
#Environment(\.managedObjectContext) var moc
#ObservedObject private var domainObject: DomainObject? = nil
var body: some View {
CustomizeView(domainObject: domainObject)
.onAppear {
...
}
}
}
-> requires domainObject in CustomizeView to be optional, not what I'm looking for
I am using the same concept (one view for editing and creating), but in my case I find myself comfortable using an optional to get the core data object. If you can live with an optional, this could work.
In this way, you just need to check if the object passed is nil: if it is, create the object, otherwise use the object passed.
In a very schematic way, the view could be:
struct EditOrCreate: View {
var coreDataObject: MyCoreDataEntity
// Optional object at initializer
init(objectPassed: MyCoreDataEntity? = nil) {
if objectPassed == nil {
coreDataObject = MyCoreDataEntity(context: thePersistentContainerContext)
} else {
coreDataObject = objectPassed!
}
}
var body: some View {
// All the text fields and save
}
}
When creating, just call EditOrCreate().
When editing, just pass the object: EditOrCreate(objectPassed: theObjectBeingShown).
You can also make coreDataObject an optional variable (which is what I did in my code), depending on how you want to handle your logic - for example, to cancel the creation before saving: in that case, you need to check for nil after the user has confirmed the creation of the new object.
Some programmers believe that "Premature Optimization Is the Root of All Evil". What I've seen happens when creating generic view code with only a small number of cases that have not yet been thought through is that after creating the generic version, you realise that you need to customise one of them, so end up trying to override the default behaviour in certain cases, which gets real messy and you would have been better off just with separate versions in the first place.
In SwiftUI, the View structs are lightweight and there is no issue with creating lots of them. Try to break your View structs up to be as small as possible then you can compose them together to form your different use cases.
The time you save could be spent on learning more about how SwiftUI works and fixing the issues in the code you posted. E.g. we don't init objects in the View struct init, or in body. Those need to run fast because that code runs quite frequently and creating objects is a comparably heavy task, also those objects that are created are immediately discarded after SwiftUI has finished building the View struct hierarchy, diffed it from last time, and updated the actual UIKit Views on screen. I highly recommend watching every WWDC SwiftUI video, there is a lot to learn and there is a lot of magic going on under the hood.
Another thing you could spend time learning is Swift generics and protocols. These are powerful ways to build reusable code using value types instead of class inheritance that we would typically use as ObjC/UIKit developers which tends to be buggy. You can read more about here: Choosing Between Structures and Classes (Apple Developer)

GCHandle, AppDomains managed code and 3rd party dll

I have looking at many threads about the exception "cannot pass a GCHandle across AppDomains" but I still don't get it....
I'm working with an RFID Reader which is driven by a DLL. I don't have source code for this DLL but only a sample to show how to use it.
The sample works great but I have to copy some code in another project to add the reader to the middleware Microsoft Biztalk.
The problem is that the process of Microsoft Biztalk works in another AppDomain. The reader handle events when a tag is read. But when I run it under Microsoft Biztalk I got this annoying exception.
I can't see any solution on how to make it work...
Here is some code that may be interesting :
// Let's connecting the result handlers.
// The reader calls a command-specific result handler if a command is done and the answer is ready to send.
// So let's tell the reader which functions should be called if a result is ready to send.
// result handler for reading EPCs synchronous
Reader.KSRWSetResultHandlerSyncGetEPCs(ResultHandlerSyncGetEPCs);
[...]
var readerErrorCode = Reader.KSRWSyncGetEPCs();
if (readerErrorCode == tKSRWReaderErrorCode.KSRW_REC_NoError)
{
// No error occurs while sending the command to the reader. Let's wait until the result handler was called.
if (ResultHandlerEvent.WaitOne(TimeSpan.FromSeconds(10)))
{
// The reader's work is done and the result handler was called. Let's check the result flag to make sure everything is ok.
if (_readerResultFlag == tKSRWResultFlag.KSRW_RF_NoError)
{
// The command was successfully processed by the reader.
// We'll display the result in the result handler.
}
else
{
// The command can't be proccessed by the reader. To know why check the result flag.
logger.error("Command \"KSRWSyncGetEPCs\" returns with error {0}", _readerResultFlag);
}
}
else
{
// We're getting no answer from the reader within 10 seconds.
logger.error("Command \"KSRWSyncGetEPCs\" timed out");
}
}
[...]
private static void ResultHandlerSyncGetEPCs(object sender, tKSRWResultFlag resultFlag, tKSRWExtendedResultFlag extendedResultFlag, tKSRWEPCListEntry[] epcList)
{
if (Reader == sender)
{
// Let's store the result flag in a global variable to get access from everywhere.
_readerResultFlag = resultFlag;
// Display all available epcs in the antenna field.
Console.ForegroundColor = ConsoleColor.White;
foreach (var resultListEntry in epcList)
{
handleTagEvent(resultListEntry);
}
// Let's set the event so that the calling process knows the command was processed by reader and the result is ready to get processed.
ResultHandlerEvent.Set();
}
}
You are having a problem with the gcroot<> helper class. It is used in the code that nobody can see, inside that DLL. It is frequently used by C++ code that was designed to interop with managed code, gcroot<> stores a reference to a managed object. The class uses the GCHandle type to add the reference. The GCHandle.ToIntPtr() method returns a pointer that the C++ code can store. The operation that fails is GCHandle.FromIntPtr(), used by the C++ code to recover the reference to the object.
There are two basic explanations for getting this exception:
It can be accurate. Which will happen when you initialized the code in the DLL from one AppDomain and use it in another. It isn't clear from the snippet where the Reader class object gets initialized so there are non-zero odds that this is the explanation. Be sure to keep it close to the code that uses the Reader class.
It can be caused by another bug, present in the C++ code inside the DLL. Unmanaged code often suffers from pointer bugs, the kind of bug that can accidentally overwrite memory. If that happens with the field that stores the gcroot<> object then nothing goes wrong for a while. Until the code tries to recover the object reference again. At that point the CLR notices that the corrupted pointer value no longer matches an actual object handle and generates this exception. This is certainly the hard kind of bug to solve since this happens in code you cannot fix and showing the programmer that worked on it a repro for the bug is very difficult, such memory corruption problems never repro well.
Chase bullet #1 first. There are decent odds that Biztalk runs your C# code in a separate AppDomain. And that the DLL gets loaded too soon, before or while the AppDomain is created. Something you can see with SysInternals' ProcMon. Create a repro of this by writing a little test program that creates an AppDomain and runs the test code. If that reproduces the crash then you'll have a very good way to demonstrate the issue to the RFID vendor and some hope that they'll use it and work on a fix.
Having a good working relationship with the RFID reader vendor to get to a resolution is going to be very important. That's never not a problem, always a good reason to go shopping elsewhere.

Core Data NSManagedObject Insert and Save Methods

Is there an easier way to do something like the following in Core Data:
Entry *entry = [[Entry alloc] init];
entry.name = #"An Entry";
[entry save];
I realize you don't have to allocate an NSManagedObject, have to insert directly into the context like the following:
Entry *entry = [NSEntityDescription insertNewObjectForEntityForName:#"Entry"
inManagedObjectContext:[self managedObjectContext]];
But this is a lot of code. Also I would like to save by just messaging rather than have to save the entire context:
NSError *error = nil;
NSManagedObjectContext *managedObjectContext = self.managedObjectContext;
if (managedObjectContext != nil)
{
if ([managedObjectContext hasChanges] && ![managedObjectContext save:&error])
{
NSLog(#"Unresolved error %#, %#", error, [error userInfo]);
abort();
}
}
Could I put these in an NSManagedObject abstract class and have my managed objects extend that abstract class? Basically, I'm just trying to encapsulate more in my models and write less code in my controllers. Any help appreciated.
You can define your own subclass of NSManagedObject, and set all of your entities to use it.
The subclass can have whatever initialiser/save patterns you define, so long as it calls the proper parent class's initialiser.
You could have a +entity method, which might link to a statically defined context (this will restrict you to a single managed object context of course, but that's not always bad as long as you can also call the more primitive initialisers when you need a second context).
You might even have a +entityWithName: method.
As for saving the context, once again you can always define a subclass and add a simple -save method which saves the context and throws an exception if the save fails. You may choose to do this with a category extending the NSManagedObject class, instead of a subclass.
Note it is impossible to save just the change you made to that one entry object. You can only save all changes to an entire managed object context. If you need to save a single record, then you need to create a temporary managed object context, make a single change in it, then save the temporary context, and then sync the temporary context change over to all other managed object context's that currently exist in the app (there is an API to do make this complicated process relatively easy).
I don't like the code you posted to save the context, for several reasons:
Don't define a managedObjectContext variable that just points to self.managedObjectContext. In almost all situations that's an extra line of code for no benefit. At best you're making your code hard to read, at worst you might be introducing bugs.
Why are you checking if it is nil? Usually you should design your code so that it cannot ever be nil. Do the nil check in the constructor of your object, and if it's nil that is a critical failure. Your whole app is completely useless for the user, and you should make it clear to the user that they can't use the app by doing something drastic, such as a crash (an error alert first would be nice, but I wouldn't bother. I'd just throw an exception).
Why are you doing a check for hasChanges? I cannot think of many situations where you would need to do this check. Perhaps your app is allowing a user to make many changes, and then saving them several minutes later? This is bad. The context should be changed milliseconds after a group of changes are made, or else you're risking data loss. Your app could crash, the phone could run out of battery, or the user might receive a phone call and your app is consuming enough RAM that the OS will terminate it instantly in order to present the "incoming call" screen. You shouldn't need to check for hasChanges because you always perform a save operation immediately after making some changes.
As I kind of mentioned before, if the save fails you should present an error to the user then throw an exception. Avoid using NSLog() in deployment code, it's really only useful for development and beta builds.
Check out
NSManagedObject+ActiveRecord.h
Inside Restkit : http://restkit.org/
It is based on :
https://github.com/magicalpanda/MagicalRecord
I am using in RestKit app, but you can adopt it quite easily.
Good luck

SharePoint and thread safety

I'm looking for articles, forum or blog posts dealing with SharePoint and thread safety? I'm quite sure there are some special aspects regarding thread safety that have to be considered when working with the SharePoint object model.
Actually I didn't find many information about this, yet.
So I'm looking forward to your answers.
Bye,
Flo
There are much worse pitfalls in the SharePoint OM than just plain old thread safety. Pay particular attention to working with objects retrieved from properties. You should always keep a pointer to an object while you work on it; example:
var list = web.List["MyList"]
list.Items[0]["Field1"] = "foo"
list.Items[0]["Field2"] = "bar"
list.Items[0].Update() // nothing is updated!
You might expect Field1 and Field2 to be updated by the final Update() call, but nope. Each time you use the indexer, a NEW reference to the SPListItem is returned.
Correct way:
SPListItem item = list.Items[0]
item["Field1"] = "foo"
item["Field2"] = "bar"
item.Update() // updated!
Just a start. Also google for pitfalls around the IDisposabe/Dispose pattern.
-Oisin
There is one issue that I often run into: when writing your own list item receivers, you need to be aware of the fact that some of the events fire asynchronously, e.g. ItemAdded() which means your code could be running in multiple threads at the same time.
So after doing some more googling and searching on the web and testing, it seems as if you don't have to care about thread-safety that much when using the MOSS object model because you're always working with non-static and unique instances.
Furthermore an exception is thrown when a object e.g. a SPWeb was altered and saved by calling the Update() method before you saved your changes (also calling the Update() method) even though you got your object first.
In the following example the instruction web11.Update() will throw an exception telling you that the SPWeb represented through the object web12 was altered meanwhile.
SPSite siteCol1 = new SPSite("http://localhost");
SPWeb web11 = siteCol1.OpenWeb();
SPWeb web12 = siteCol1.OpenWeb();
web12.Title = "web12";
web12.Update();
web11.Title = "web11";
web11.Update();
So the thready-safety seems to be handled by the object model itself. Of course you have to handle the exceptions that might be thrown due to race conditions.

IDynamicObject implementation ignores multiple property invocations

I've implemented IDynamicObject in C# 4, return a custom MetaObject subclass that does simple property getter/setter dispatch to a Dictionary. Not rocket science.
If I do this:
dynamic foo = new DynamicFoo();
foo.Name = "Joe";
foo.Name = "Fred";
Console.WriteLine(foo.Name);
Then 'Joe' is printed to the console... the second call to the 'Name' setter is never invoked (never steps into my custom dispatcher code at all).
I know the DLR does callsite caching, but I assumed that wouldn't apply here. Anyone know what's going on?
Whatever MetaObject you're returning from (Bind)SetMember will be cached and re-used in this case. You have 2 dynamic sites doing sets. The 1st call will cache the result in an L2 cache which the 2nd site will pick up before asking you to produce a new rule.
So whatever MetaObject you're returning needs to include an expression tree that will update the value. For example it should do something like:
return new MetaObject(
Expression.AssignProperty(this.Expression, value.Expression),
Restrictions.TypeRestriction(this.Expression, this.Value.GetType());

Resources