Core Data Unit Tests with in-memory store crash - macos

I am attempting to test my application's interaction with CoreData using an in-memory store, but the code crashes when I attempt to cast the object given from this call:
let newEntity: AnyObject = NSEntityDescription.insertNewObjectForEntityForName("File", inManagedObjectContext: moc)
let newFile = newEntity as RSFile
RSFile is set properly in the Class field of the core data model and included in , and this code works fine in the normal application. I have checked that the Managed Object Model is being properly created, and everything seems to be setup properly, but I end up in the machine code with a "dynamic cast failed" string a few lines above the breakpoint.
Additionally, if I cast newEntity to an NSManagedObject and place a breakpoint so that I can inspect it at runtime, everything appears valid there, so the issue is solely with the cast. I've looked at other suggestions but I can't find anything missing from my configuration. Any ideas as to what could be going wrong?
Update
I created an example project that demonstrates both a working core data interaction while the apps running, and the crash when you run the tests.
https://github.com/kujenga/CoreDataIssue

In a simple test project I made it work like this:
Make sure the classes are not added also to the test target.
Import your MyApp package on top of your test class.
Cast with as?.
Like this:
var newEntity = NSEntityDescription.insertNewObjectForEntityForName(
"File", inManagedObjectContext: context) as? PSFile
EDIT
After ascertaining that the above does indeed return nil (only in the test class), here is my working solution:
Make all the classes you need in the test public, including the managed object subclasses.
In case of the managed objects, you also need to make the attributes (properties) that you intend to access public.
Don't add the classes to the test target (if you do, the cast will fail).
Instead, add import YourAppName to the test file.
Use an unconditional cast.
Like this [tested]:
let newEntity = NSEntityDescription.insertNewObjectForEntityForName(
"File", inManagedObjectContext: moc) as! RSFile

Related

Can I Write a Spotlight Importer in Swift?

I need to write a Spotlight Importer for an application that I've written in Swift, and am referring to the official Apple guide for Writing a Spotlight Importer.
It seems straightforward enough, however creating a Spotlight Importer project creates a default setup for an Objective-C implementation. Now, working with Objective-C isn't a huge problem (I've used it plenty of times in the past) but everything I've written for my application is in Swift, so I'd really I'd like to write the importer in Swift too to avoid switching between languages, and also so I can share some of the code that I've already done for reading/writing files.
Firstly, is it possible to write a Spotlight Importer using Swift instead of Objective-C? And if it is, where should I start (e.g- if I take the Objective-C starting point, what would I do to switch over to Swift instead)?
It took me a bit of time to get this to work.
Instead of adding Swift code to the mdimporter, I import an embedded framework already setup for my app.
I removed all the example code except main.c and GetMetadataForFile.m.
In the latter I import my framework where all the functionality now resides as Swift code.
The built mdimporter is added to the app.
In the File Inspector set Location to Relative to Build Products.
The app then adds the mdimporter with a Copy Files Build Phase.
Destination: Wrapper
Subpath: Contents/Library/Spotlight
The following needs to be added to the Run Search Paths build setting, as we are linking to the app's embedded frameworks.
#loader_path/../../../../../Frameworks
If you get compiler error that the framework module can't be found when building the app, depending on how your workspace is set up, you might need to modify your app's Scheme.
Turn off Parallelize Build
Add the Build targets in this sequence:
Frameworks project(s)
mdimporter project
App project
The additional benefit of having all the logic in a framework, is that it can be prototyped and verified in a Playground. A million times easier than debugging an mdimporter plugin.
Yes, it is possible to write a Spotlight Importer entirely* in Swift!
*except for a few lines of code in main.m
I've just published one here: https://github.com/foxglove/MCAPSpotlightImporter
Here's a detailed blog post about the implementation process:
https://foxglove.dev/blog/implementing-a-macos-search-plugin-for-robotics-data
The difficult part of this is implementing a plugin that's compatible with the CFPlugIn architecture. (The MDImporter-specific logic is relatively minimal.) The CFPlugIn API is based on Microsoft's COM and Apple's docs are almost 20 years old.
The plugin is expected to be a block of memory conforming to a certain memory layout — specifically, the first value in the block must be a pointer to a virtual function table (vtable) for the requested interface (in the case of a MDImporter, this is either MDImporterInterfaceStruct or MDImporterURLInterfaceStruct) or the base IUnknown interface. This layout is documented here.
I wanted to organize the Swift code into a class, but you can't control the memory layout of a Swift class instance. So I created a "wrapper" block of memory which holds the vtable and an unsafe pointer to the class instance. The class has a static func allocate() which uses UnsafeMutablePointer to allocate the wrapper block, create and store the class instance in it, and also initialize the vtable.
The vtable implements the standard COM base interface (IUnknown) functions (QueryInterface, AddRef, and Release) by grabbing the class instance out of the wrapper and calling the queryInterface(), addRef(), and release() methods on the instance. It also implements the Spotlight-specific ImporterImportURLData function (or ImporterImportData). Unfortunately, in my testing, it seemed like Spotlight did not pass the correct pointer to the wrapper struct as the first argument to ImporterImportURLData, so it was impossible to call a method on the class instance, so the function that actually imports attributes for a file had to be a global function. For this reason I wasn't able to make the plug-in implementation a more generic class that could be used with any interface — it has to be tied to a specific global importer function.
I'd encourage you to view the full source on GitHub, but in the interest of not being a link-only answer, here's the core functionality:
final class ImporterPlugin {
typealias VTable = MDImporterURLInterfaceStruct
typealias Wrapper = (vtablePtr: UnsafeMutablePointer<VTable>, instance: UnsafeMutableRawPointer)
let wrapperPtr: UnsafeMutablePointer<Wrapper>
var refCount = 1
let factoryUUID: CFUUID
private init(wrapperPtr: UnsafeMutablePointer<Wrapper>, factoryUUID: CFUUID) {
self.wrapperPtr = wrapperPtr
self.factoryUUID = factoryUUID
CFPlugInAddInstanceForFactory(factoryUUID)
}
deinit {
let uuid = UUID(factoryUUID)
CFPlugInRemoveInstanceForFactory(factoryUUID)
}
static func fromWrapper(_ plugin: UnsafeMutableRawPointer?) -> Self? {
if let wrapper = plugin?.assumingMemoryBound(to: Wrapper.self) {
return Unmanaged<Self>.fromOpaque(wrapper.pointee.instance).takeUnretainedValue()
}
return nil
}
func queryInterface(uuid: UUID) -> UnsafeMutablePointer<Wrapper>? {
if uuid == kMDImporterURLInterfaceID || uuid == IUnknownUUID {
addRef()
return wrapperPtr
}
return nil
}
func addRef() {
precondition(refCount > 0)
refCount += 1
}
func release() {
precondition(refCount > 0)
refCount -= 1
if refCount == 0 {
Unmanaged<ImporterPlugin>.fromOpaque(wrapperPtr.pointee.instance).release()
wrapperPtr.pointee.vtablePtr.deinitialize(count: 1)
wrapperPtr.pointee.vtablePtr.deallocate()
wrapperPtr.deinitialize(count: 1)
wrapperPtr.deallocate()
}
}
static func allocate(factoryUUID: CFUUID) -> Self {
let wrapperPtr = UnsafeMutablePointer<Wrapper>.allocate(capacity: 1)
let vtablePtr = UnsafeMutablePointer<VTable>.allocate(capacity: 1)
let instance = Self(wrapperPtr: wrapperPtr, factoryUUID: factoryUUID)
let unmanaged = Unmanaged.passRetained(instance)
vtablePtr.initialize(to: VTable(
_reserved: nil,
QueryInterface: { wrapper, iid, outInterface in
if let instance = ImporterPlugin.fromWrapper(wrapper) {
if let interface = instance.queryInterface(uuid: UUID(iid)) {
outInterface?.pointee = UnsafeMutableRawPointer(interface)
return S_OK
}
}
outInterface?.pointee = nil
return HRESULT(bitPattern: 0x8000_0004) // E_NOINTERFACE <https://github.com/apple/swift/issues/61851>
},
AddRef: { wrapper in
if let instance = ImporterPlugin.fromWrapper(wrapper) {
instance.addRef()
}
return 0 // optional
},
Release: { wrapper in
if let instance = ImporterPlugin.fromWrapper(wrapper) {
instance.release()
}
return 0 // optional
},
ImporterImportURLData: { _, mutableAttributes, contentTypeUTI, url in
// Note: in practice, the first argument `wrapper` has the wrong value passed to it, so we can't use it here
guard let contentTypeUTI = contentTypeUTI as String?,
let url = url as URL?,
let mutableAttributes = mutableAttributes as NSMutableDictionary?
else {
return false
}
var attributes: [AnyHashable: Any] = mutableAttributes as NSDictionary as Dictionary
// Call custom global function to import attributes
let result = importAttributes(&attributes, forFileAt: url, contentTypeUTI: contentTypeUTI)
mutableAttributes.removeAllObjects()
mutableAttributes.addEntries(from: attributes)
return DarwinBoolean(result)
}
))
wrapperPtr.initialize(to: (vtablePtr: vtablePtr, instance: unmanaged.toOpaque()))
return instance
}
}
Finally, I created an #objc class that exposes this allocate function to Obj-C, where I can call it from main.m, and return the pointer to the wrapper block from the factory function. This was necessary because I didn't want to use the unstable #_cdecl attribute to expose a Swift function directly to the plug-in loader.
#objc public final class PluginFactory: NSObject {
#objc public static func createPlugin(ofType type: CFUUID, factoryUUID: CFUUID) -> UnsafeMutableRawPointer? {
if UUID(type) == kMDImporterTypeID {
return UnsafeMutableRawPointer(ImporterPlugin.allocate(factoryUUID: factoryUUID).wrapperPtr)
}
return nil
}
}
// main.m
void *MyImporterPluginFactory(CFAllocatorRef allocator, CFUUIDRef typeID) {
return [PluginFactory createPluginOfType:typeID factoryUUID:CFUUIDCreateFromString(NULL, CFSTR("your plugin factory uuid"))];
}
See my blog post for more details.
Since Apple introduced Swift as a language to be perfectly compatible with any existing Objective-C project I would suggest you just start with whatever makes things easier for you.
If you know Swift best then nothing keeps you from using that – for whatever project you might want. If you want to follow a tutorial that was written for Objective-C and not updated for Swift yet, I think you have two choices (I'd personally recommend going for the second option for now):
Write the same logic written in Objective-C within the tutorial now in Swift from scratch (nearly everything possible in Objective-C is easily possible with Swift, too). For that you need to understand the basics of Objective-C and the corresponding syntax and features in Swift though.
Start with Objective-C to follow the tutorial and keep things easier at the beginning (no need to really understand the tutorials details). Then use the great possibility of mix and matching Swift code alongside Objective-C code to customize the code for your needs or to extend it with your own pre-existing classes.
More specifically on the second option:
If you want to write new classes just use Swift – you can perfectly use everything written in Objective-C from within Swift and vice versa. If you feel you need to change classes already written in Objective-C you have these options: Extend the class written in Objective-C with a new Swift class, re-write that specific file in Swift or just edit the Objective-C file directly.
To learn more on how to mix and match Swift code alongside Objective-C I recommend reading Apples official documentation. It's part of the free iBook "Using Swift with Cocoa and Objective-C" written by Apple engineers for developers.
Unfortunately Apple actually does seem to provide their template for a Spotlight Importer from within XCode for Objective-C only at the moment. Don't know why this is though – I can't see anything stopping them from supporting Swift. We should probably report this with Apples Bug Reporter to stress the fact that people are actually asking for this.
Hope I didn't overlook anything here, otherwise my answer will be pointless. ^^
UPDATE (request)
Here are some steps on where to begin to implement the first approach:
First create a Spotlight Importer project with the latest XCode version
– Create a new "Cocoa Touch" class named exactly the same as your pre-created main Objective-C classes (e.g. "MySpotlightImporter")
Choose Swift and "Create Bridging Header" when asked during class creation
– Re-implement the code written in the ObjC-MySpotlightImporter class within the Swift class (you might want to create a Cocoa App with Core Data support in Swift and Objective-C to get some idea of their differences)
– I'm not sure if you can rewrite the GetMetaDataFile.m in Swift, too, I couldn't figure that out in my test, so you maybe need to keep it around (for now)
– In case you receive any errors along the way that point to some missing configuration just search for the related files/classes in the projects "Build settings" and apply your changes there
I hope this helps to get you started and is specific enough. I tried to do the necessary changes myself in order to provide an example project in Swift but unfortunately I couldn't get it working in a limited time. You may want to consider providing your code publicly though (e.g. on GitHub with a link posted here) in case you decide to port it yourself so others can profit from this, too.
Good luck!

Implementing a NSService method

I created a Service for my app, the menu appears correctly, but I still have a problem with the method called when the menu item is activated.
In AppDelegate.swift I have:
func applicationDidFinishLaunching(aNotification: NSNotification) {
NSApplication.sharedApplication().servicesProvider = ServiceProvider()
NSUpdateDynamicServices();
}
And the class ServiceProvider is:
import Cocoa
class ServiceProvider {
func serviceTest(pasteboard: NSPasteboard, userData: String, error: NSErrorPointer) {
// code here
}
}
When the service is activated I want to send some information to the components of my app, for example, to change the text of a label. How can I do this? I tried to get the mainWindow inside the function serviceTest to access its components, but it returned nil.
I am trying to do something similar to the Safari service that you select some text, and right-click > services > search with google. This open Safari and search for the selected text. Or something similar to add a new task to Wunderlist, that gets the selected text and create a new task in the app.
I really appreciate some help to solve this issue.
This is just the general problem of getting access to objects in various parts of a program. There are two general mechanisms: start with a well-known object or have the object(s) you need passed in to you by the part of the code which knows about both object.
For example, you can get to the application delegate using NSApplication.sharedApplication().delegate. You would then cast it to your custom app delegate class and access its properties.
However, it's probably better to avoid relying on pseudo-global variables if there's a simple alternative, and there is. Give your ServiceProvider class the necessary properties to track the objects it needs (like the app delegate). In the app delegate code which creates the ServiceProvider instance, simply set those properties. That may be in statements to set properties after it has been created or you could pass it in to the initializer method as an argument. Obviously, you'd need to declare that initializer method to take the argument and store it in your instance variable.

How can I modify the fixture my custom theory data attribute creates for AutoFixture?

I'm really appreciating the power of AutoFixture coupled with XUnit's theories. I've recently adopted the use of encapsulating customizations and providing them to my tests via an attribute.
On certain occasions, I need a one-off scenario to run my test with. When I use an AutoDomainDataAttribute, like above, can I ask for an IFixture and expect to get the same instance created by the attribute?
In my scenario, I'm using MultipleCustomization by default for collections, etc. However, in this one case, I want only a single item sent to my SUT's constructor. So, I've defined my test method like so:
[Theory, AutoDomainData]
public void SomeTest(IFixture fixture) {
fixture.RepeatCount = 1;
var sut = fixture.CreateAnonymous<Product>();
...
}
Unfortunately, I'm getting an exception when creating the anonymous Product. Other tests work just fine, if I ask for a Product as a method parameter with those attributes. It's only an issue in this particular case, where I'm hoping that the fixture parameter is the same one created by my AutoDomainDataAttribute.
Product's constructor expects an IEnumerable that normally gets populate with 3 items, due to the customizations I have in-place via AutoDomainData. Currently, my DomainCustomization is a CompositeCustomization made up of MultipleCustomization and AutMoqCustomization, in that order.
The exception is: "InvalidCastException: Unable to cast object of type 'Castle.Proxies.ObjectProxy' to type 'Product'."
If you need the same Fixture instance as the one active in the attribute, you can inject the Fixture into itself in a Customization, like this:
public class InjectFixtureIntoItself : ICustomization
{
public void Customize(IFixture fixture)
{
fixture.Inject(fixture);
}
}
Just remember to add this to your CompositeCustomization before AutoMoqCustomization, since IFixture is an interface, and if AutoMoqCustomization comes first, you'll get a Mock instance instead - AFAICT, that's what's currently happening with the dynamic Castle proxy.
However, if you really need a Fixture instance, why not just write a regular, imperative test method:
[Fact]
public void SomeTest()
{
var fixture = new Fixture().Customize(new DomainCustomization());
fixture.RepeatCount = 1;
var sut = fixture.CreateAnonymous<Product>();
// ...
}
That seems to me to be much easier... I occasionally do this myself too...
Still, I wonder if you couldn't phrase your API or test case in a different way to make the whole issue go away. I very rarely find that I have to manipulate the RepeatCount property these days, so I wonder why you would want to do that?
That's probably the subject of a separate Stack Overflow question, though...

what does "failed to load window nib file" mean?

I'm working on my first Cocoa application, and I'm hoping very much that
[NSWindowController loadWindow]: failed to load window nib file 'Genius Document'
means that there's something very specific I've done wrong, because if I have to go back and redo all the bindings I'll want to kill myself.
FWIW, I'm working with a document-based application that has (so far) only one XIB file and no NIB files.
I can post code/screenshots of my bindings but in case that's not necessary I didn't want to make people wade through them.
Thanks for the help.
The error you have described ultimately occurs because a call to load the nib file is failing. Make sure you've supplied the correct name for your Interface Builder file.
You can supply the correct value in a number of ways (depending on your use of AppKit), so I'll lay out the two most common possibilities and you can track down which one applies to you. Given what you've said in your question, I suspect you'll be dealing with the first scenario.
NSDocument windowNibName
If you are relying on the document architecture's defaults, you are probably not making the call in question directly. Instead, the framework makes the call on your behalf, using whatever nib name you specify on the given document class.
For example, if you were to make a new document-based project with a document class of "XYZDocument," the Xcode template would provide you with a basic XYZDocument class and a XYZDocument.xib file. The XYZDocument implementation file would have the following in it:
// XYZDocument.m
- (NSString *)windowNibName {
return #"XYZDocument"; // this name tells AppKit which nib file to use
}
If you were to alter this value, you would create the [NSWindowController loadWindow] error.
NSWindowController initialization methods
If you are making this call yourself (perhaps on your own subclass of NSWindowController), then you will have written a line like the following.
// XYZWindowController.m (a subclass of NSWindowController)
- (id)init {
self = [super initWithWindowNibName:#"XYZDocument"];
if (self) {
// initializations
}
return self;
}
If the string argument you've supplied does not match the name of the nib file, the same error will occur.
I ran a Clean (Cmd-Shift-K) in Xcode and that solved the issue for me.

How to parse the contents of a foreign file created with NSKeyedArchiver

I need to be able to compare two versions of a plist file created with NSKeyedArchiver. In particular, it's the "elements" file created in Xcode for a .xcdatamodeld file.
Since I have not created this file myself I can not recreate its object model. Instead, I need to understand which classes and keyed properties the archive contains.
Ideally, I want to create a tree containing strings representing the names of classes along with their property names and values. I assume that all this information is stored in the archive, so it should be possible to generically parse this archive, right?
I've read about NSKeyedUnarchiver and its delegate. I've only gotten as as as this:
Unarchive the file data:
NSKeyedUnarchiver *unarchiver = [[NSKeyedUnarchiver alloc] initForReadingWithData:data];
unarchiver.delegate = self;
id graph = [unarchiver decodeObjectForKey:#"root"];
Here's the delegate method that gets called when an unknown class is requested. I return a proxy class here in which I hope to collect its values:
- (Class)unarchiver:(NSKeyedUnarchiver *)unarchiver cannotDecodeObjectOfClassName:(NSString *)name originalClasses:(NSArray *)classNames
{
NSLog(#"wants: %#", name);
return [ObjProxy class];
}
The proxy class implements
- (id)initWithCoder:(NSCoder *)aDecoder
in which I do not know how to proceed, not knowing the actual properties of the classes. NSCoder doesn't seem to provide any function to learn of the available keys. Is there a trick to get to them, maybe by overriding some of the lower level objc methods?
So far, with this little code shown above, when parsing the "elements" file, I only get the request for one class, "XDPMModel", and then it's done.
Any ideas how to get this working, i.e. traverse the tree deeper?
You can use PlistExplorer, it's a Cocoa Tool to inspect files written by NSKeyedArchiver.
I've done exactly this before, to decode objects stored in the preferences file for Panic's Coda. What I did was to use class-dump on the app (in your case Xcode and its related frameworks), which allows you to see the properties of the real objects, and use these to create proxy objects that match those properties. You can then use NSKeyedUnarchiver successfully and query the proxy objects for their values.
It's a fairly laborious process but it works perfectly. In my case I was working with a user defaults plist so I only had to define a couple of these proxy classes for the objects I was interested in, but I would imagine that you'll have to define quite a few for Xcode.
I'd also be very interested to know if there's a way to do this without having to go the class-dump route (possibly, as you say, via some of the lower-level Objective-C functions) because it would greatly simplify this type of reverse engineering.

Resources