Using Xcode 12, and starting with the default XIB-based swift desktop app, I add a Model class, descended from NSObject with a single stringValue property. In the XIB file I instantiate the Model class, and add a text field to the default window, and bind the value of the text field to the stringValue property of my Model instance. The project builds and runs, and any value I set in the initializer of the Model class displays in the text field.
Here is my Model class:
import Foundation
#objc public class Model : NSObject {
#objc dynamic public var stringValue: NSString
override init() {
stringValue = "some string"
}
}
The full project is available here:
https://github.com/thomasmarschall/KvoLab2023
I started with a bit more complicated setup involving a separate library and framework, but my current setup seems to be super straightforward.
Having done all of this, Xcode displays a grey flag in the Model Key Path field of the text field value binding, and the tool tip for the flag reads "xcode cannot resolve the entered keypath". Also, the autocomplete in the key path field does not work. How can I resolve these issues? Any help would be appreciated.
Related
I have created 2 core data entities and then created NSManagedObject Subclasses for them from the editor menu.
However when I run my app I get errors on every line of all the files for some reason.
Here is an example, these errors are the same for both entities created files.
File Code was auto generated so i can apste it here but not sure of its use
import Foundation
import CoreData
extension UserExercise {
#nonobjc public class func fetchRequest() -> NSFetchRequest<UserExercise> {
return NSFetchRequest<UserExercise>(entityName: "UserExercise");
}
#NSManaged public var id: Int16
#NSManaged public var name: String?
#NSManaged public var reps: Int16
#NSManaged public var sets: Int16
#NSManaged public var weight: Int16
#NSManaged public var relationship: NSSet?
}
// MARK: Generated accessors for relationship
extension UserExercise {
#objc(addRelationshipObject:)
#NSManaged public func addToRelationship(_ value: UserRoutine)
#objc(removeRelationshipObject:)
#NSManaged public func removeFromRelationship(_ value: UserRoutine)
#objc(addRelationship:)
#NSManaged public func addToRelationship(_ values: NSSet)
#objc(removeRelationship:)
#NSManaged public func removeFromRelationship(_ values: NSSet)
}
Errors are:
Command/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/swiftc failed with exit code 1
Invalid redeclaration of 'UserRoutine'
'UserExercise' is ambiguous for type lookup in this context
#NSManaged only allowed on an instance property or method
Theres too many to list its basically these repeated over and over
Xcode by default manage generation of these subclasses for you. If you want to manage generation of them yourself then:
Select your entities in the data model.
Find Codegen in the utilities pane(right pane) and set it to Manual/None.
Clean and build.
The current default in Xcode is to automatically create subclasses of NSManagedObject for you in the /Users/<your user name>/Library/Developer/Xcode/DerivedData/AppName-agkwmibzbopevjgfajlcbyixzyev/Build/Intermediates/AppName.build/Debug-iphonesimulator/AppName.build/DerivedSources/CoreDataGenerated/Modeldirectory; The DerivedData directory is where Xcode saves automatically generated code. You are redeclaring the same subclass by doing Editor>Create NSManagedObject Subclass... that is why you are getting the "Invalid redeclaration of 'UserRoutine' 'UserExercise' is ambiguous for type lookup in this context #NSManaged only allowed on an instance property or method" error. To resolve the errors and manually create a subclass of NSManagedObjects what you need to do is:
Open terminal and navigate to /Users/<your user name>/Library/Developer/Xcode/DerivedData/AppName-agkwmibzbopevjgfajlcbyixzyev/Build/Intermediates/AppName.build/Debug-iphonesimulator/AppName.build/DerivedSources/CoreDataGenerated/Model
Run this command: rm -rf * (now be careful with this command, run it only when you get to the final directory where the generated codes are or you'll break your project for good)
Delete your current data model
Create a new data model
Select your new data model's entity (do this for each entity within the data model) and go to its attributes inspector and set its Codegen to Manual/None Before the first run after you have created a new data model.
Create a subclass of NSManagedObject by going to Editor>Create NSManagedObject Subclass...
Your errors should disappear.
Hope this helped!
A simple approach that worked for me .... You can find these by choosing an entity and clicking on the Data Model Inspector at the top right . Do this for all of your entities
Its important to FIRST set Module to "Current Product Module" AND Codegen to "Manual/None"
Only then, SECOND: Editor -> Create NSManagedObject subclass.
This is for Swift 3.0 and Xcode 8.2.1(8C1002)
Not sure why you would manually navigate to the project when you can just instead delete the files directly from Xcode.
Find all of your generated files from the xcdatamodeld, inside of your project navigator. Delete all of the files and make sure you move to trash, do not remove references otherwise you're going to have to manually delete the files from:
/Users//Library/Developer/Xcode/DerivedData/AppName-agkwmibzbopevjgfajlcbyixzyev/Build/Intermediates/AppName.build/Debug-iphonesimulator/AppName.build/DerivedSources/CoreDataGenerated/Model
Ok so after you've deleted the files, open your xcdatamodeld, select all of your entities, and in the Utilities panel, select Data Model Inspector button, and make sure that Codegen is set to "Manual/None".
Select your xcdatamodeld and make sure that that Codegen is set to "Manual/None"
Keep all of your entities selected and click Editor > Create NSManagedObject Subclass, make sure to select the folder and drag and drop your generated files in your Model sub-group and your Generated sub-group.
This worked for me and it should work for you too.
I hope that I have helped you.
I also ran into this bug. I fixed it by deleting the old generated entity subclasses and creating it again and for the group I selected the workspace instead of the project or folder in the project, and the subclasses got saved above the project file. It looks weird but it fixed the issue. Also if i move the files into the folder inside the project the error reappears.
I ran into this issue during unit testing due to recreating my NSPersistentContainer over and over again in every unit test. It looks like loading the same managed object model repeatedly could lead to this.
My resolution was to use a single shared instance across all of my unit tests and do clean up between them accordingly.
I was getting the "... is ambiguous for type lookup in this context" error when building a simple SwiftUI Mac app for testing this issue after running Editor/Create NSManagedObject subclass..." with Xcode Version 13.4 (13F17a) on macOS Monterey 12.3.1.
I found a solution in deselecting/unchecking the checkbox for "Targets" in the final dialog before clicking "Create". This checkbox was selected by default. Clearing it and clicking "Create" resulted in a successful build.
This results with the subclass files at the top level of the project structure:
I need to create the GUI for setting my app preferences. Since I am not able to get multiple instances of the SharedUserDefaultsController in multiple storyboard scenes, I created a simple proxy for it. I'm trying to bind a text field content to a specific values of the SharedUserDefaultsController through the proxy which is represented in IB via an NSObject added to the scene that should contain the binding. For the binding I use self.defaults.values.default_key where default_key is a defined key in the StandardUserDefaults for my application.
When I try to show the view that contains the binding, though, it is not shown and the only displayed message in the console is
Missing placeholder for identifier UpstreamPlaceholder-37m-v1-XT6
What am I doing wrong? In the storyboard source there's no trace of that identifier. Here's the code of the SharedUserDefaultsControllerProxy class that I created:
import Cocoa
class SharedUserDefaultsControllerProxy: NSObject{
var defaults = NSUserDefaultsController.sharedUserDefaultsController()
override init() {
super.init()
}
}
I have an Objective-C model class MyType. This class is used in Swift code:
NSEntityDescription.insertNewObjectForEntityForName("MyType", inManagedObjectContext: context) as! MyType
The as! cast results in the error message
Core Data: Could not cast value of type 'MyType_MyType_2' (0x7be99a30) to MyType (0xf33db74).
If I cast it as NSManagedObject it works. When I print the result, I can nevertheless see, that it is an actual instance of MyType:
<MyType: 0x7ae06d50> (entity: MyType; id: 0x7aeba6d0 <x-coredata:///MyType/t957F2860-85F8-46E0-B6D6-4D1DF6C4EC613> ; data: {
...the fields...
})
What is happening here? And where does the name MyType_MyType_2 come from?
When I had this issue, it was because I had forgotten to set the "class" on the entity. This is what I came up with:
Click on .xcdatamodelId file in your file structure/project
navigator pane (far left).
Select the entity that you are having issues with.
In the Utilities pane (far right), look for the icon that looks like a 1997 cell phone, the Data Model Inspector.
Under the entity settings, you should see two fields, "Name" and "Class" - set up "Class" with the name of the class you are using (typically the same as "Name").
You'll even notice before you follow these steps that the default "class" is NSObject, reflecting the error message. I found some programatic ways to do this too, but this seemed like the simplest/quickest solution.
I should note that my model WAS written in Swift, so I did have to add the #objc(Entity) interoperability reference mentioned by #zellb. But that shouldn't make a difference in the solution as long as you are doing that part properly (and that would cause a different unrelated error from my understanding).
Set Entity Class Name
Set Module "Current Product Module" like below
just try this:
#objc(MyType)
public class MyType: NSManagedObject {
// your class
}
instead of this:
class MyType: NSManagedObject {
// your class
}
I had mistakenly set a "parent entity" in one of my entities in the data model inspector in the entity section. I mistakenly thought that referred to the destination of a one-to-many relationship.
Setting it back to "no parent entity" fixed the problem, although I did have to delete and reinstall the app in the simulator to deal with the messed up core data database.
Running the following code aborts in the return line
Type is not Workout
Could not cast value of type
'NSManagedObject_Workout_' (0x7fcca20620f0) to
'AppName.Workout' (0x100ea5f40)).
The part inside if let... is never executed.
func createWorkoutWithName (name: String) -> Workout? {
let entityName = NSStringFromClass(Workout.classForCoder())
let newEntity = NSEntityDescription.insertNewObjectForEntityForName(entityName, inManagedObjectContext: managedObjectContext)
if let newEntity = newEntity as? Workout {
newEntity.name = name
}
NSLog("createWorkoutWithName: Type is not Workout")
return (newEntity as! Workout)
}
I had this problem in the past and I solved it in XCode 6.x by going in the entity inspector and setting Class = AppName.Workout
One of several answers that suggests this solution is
How come I can cast to NSManagedObject but not to my entity's type?
XCode 7 adds a new twist to this problem:
When I set
Class = AppName.Workout
in the entity inspector, XCode 7 changes the class name automagically to
Class = AppNameWorkout
by removing the dot between AppName and ClassName.
So how can I do this in XCode 7 when I can't set a dot between AppName and ClassName?
Go to your cdatamodel..where you declared your entity..There is a Default Configuration below the Entity. Check the Class column against your entity. By default this will have a dot prefixed. Remove the dot prefix .And it should work. And from what i see is you do not have to prefix your entity class name with the module name in Xcode 7. Hence you cannot use a dot in the class name.I am a newbie in iOS development. So i might not be totally right. But removing the dot prefix solved my issue in Xcode 7.
You need two fixes:
First: Set your entity class name as your entity name. For example:
Entity name = Entity
Class name = Entity
Second: add this code above your entity class file:
#obj(Entity name)
For example:
#obj(Entity)
Class Entity: NSManagedObject {
...
}
The combination of these solutions and the link you provided got me to the solution, but it took me a while to piece it all together. This is what I came up with (and it was basically just an oversight):
Click on .xcdatamodelId file in your file structure/project
navigator pane (far left).
Select the entity that you are having issues with.
In the Utilities pane (far right), look for the icon that looks like a 1997 cell phone, the Data Model Inspector.
Under the entity settings, you should see two fields, "Name" and "Class" - set up "Class" with the name of the class you are using (typically the same as "Name").
Thats where I messed up, even though all my other entities had this set, I had forgotten to set this on this particular entity. You'll even notice before you follow these steps that the default "class" is NSObject, reflecting the error message. Some of the other solutions here likely ultimately do the same thing, but I found this the simplest/quickest solution.
I should note that I already had some of the other items noted set, like the #objc(Entity) interoperability reference.
This is for XCode 6 and Swift...
I'm trying to make a fetch request to the managed object context but it's not returning the correct subclass.
I have already set the subclass in the data model data modeler configuration to the name of my custom subclass and in the code, it is extending the NSManagedObject class.
Any ideas?
Just figured out the solution.
I had to add the #objc attribute to allow the class to be compatible with Objective-C.
Now the fetch request is returning a correct result of Tasks[]
import Foundation
import CoreData
#objc(Task) // make compatible with objective-c
class Task : NSManagedObject
{
#NSManaged var note: String!
#NSManaged var completed: Bool
}
Reference: https://developer.apple.com/library/content/documentation/Swift/Conceptual/BuildingCocoaApps/InteractingWithObjective-CAPIs.html#//apple_ref/doc/uid/TP40014216-CH4-XID_36
Using #objc(Task) seems to be working but you could also just edit the data model data modeler configuration to the name ToDoList.Task instead of just Task. That will work too and avoid Class conflicts if Task is used anywhere else in the Objective-C code.
Check to make sure that in the "Entity" inspector (right side of the screen, Utilities pane) when Task is selected in your Model that its Class field is properly filled in with "Task" (it's blank by default).