Binding in OSX: class is not key value coding-compliant for the key {name of binding var} - swift

I was trying to follow instructions from Learning Swift book (creating note taking app) by B.A. Paris & Co, but faced with the following problem with binding. I am mostly practicing iOS programming, so binding concept is new for me.
Steps I made (tried both xcode 9 beta 5 and 8.3.3):
Create OSX Cocoa App (not using storyboard, document based app – on, document
extension “test”, don’t use core data)
Add “var text = NSAttributedString()” to Document.swift
Add a NSTextView to Document.xib
In Bindings inspector of NSTextView setting “Attributed String” to File’s owner “self.text” (Model Key Path)
And I see exclamation mark with notion “Xcode cannot resolve the entered key path”
Build is successful, but when I run it says “2017-09-03 22:17:40.739643+0200 test3[6017:424072] [<test3.Document 0x6180000c3410> valueForUndefinedKey:]: this class is not key value coding-compliant for the key text.”
I tried to control drag from Xib to Swift, it warns that “Xcode cannot locate the class Document in the current workspace”.
I tried to convert to workspace instead of proj, checked the file owner, checked the stackoverflow threads witch relate to the error – but they mostly concerned about some connection made by mistake or non actual connections (I can delete the connection, I know what connection is wrong, the question is how to make it right). So far could not find solution.
Thanks in advance

You need to declare the text property with the #objc attribute to make it accessible via dynamic dispatch like Key-Value Coding.
Also, because you want modifications of the property to be observable via Key-Value Observing (for Bindings), you need to tell Swift to always dispatch modifications of it dynamically. So, you need to use the dynamic modifier on the declaration, too:
#objc dynamic var text = NSAttributedString()

Related

Xcode Playgrounds: Source files are unable to be accessed by each other

I am creating a playground in Xcode and I do not understand why the "Sources" files cannot talk to each other. I am using SpriteKit which means it is ideal to have one swift file per scene, in my case I have one scene per level. I cannot use a quick workaround and add everything into one massive file... there has to be a better way. Both classes for the two swift files are public. You should be able to access them. Thanks!
I get this error when I try to an object from one class, LevelScene, in the other class TitleScene.
After this
let levelScene = LevelScene(fileNamed: "LevelScene")
This happens
Cannot find 'LevelScene' in scope
I am aware of this post. This solution still does not work for me.
Xcode playgrounds can't access swift files in Sources folder
I am on Xcode 12.4.
Thanks!
You need to declare all your classes/struct in each file as public.
So, if you have defined a struct like this in a file:
struct Node {
var id: Int
}
You need to declare is like so:
public struct Node {
var id: Int
}
Then your code should work. You can use a struct from one file in another file as long as you declare them as public. Similar concept goes for any functions/methods inside those structs/classes. Even with this solution, you may find Xcode 12.4 complaining about not finding the type in scope. That, I believe, is a known bug. I have the same bug on my Xcode 12.4. I am able to build and run the code even with that error.

Value of type 'Category' (aka 'OpaquePointer') has no member 'name'

I'm working with Swift in Xcode and I receive the following error: -- Value of type 'Category' (aka 'OpaquePointer') has no member 'name' -- and I've looked everywhere but I can't find a solution.
Does someone know what to do?
Here is a screenshot:
Thanks for your help!
I also had this occur when attempting the exercise in the Angela Yu course where Category is a core data entity. I was using Xcode 11.3.1. After several attempts of setting the Module to Current Product Module and Codegen to Class Definition followed by Ctrl-B's to rebuild, I still received the error. However, restarting Xcode solved the problem and code completion was then able to suggest the name attribute/property.
I had same issue while been going through Angela Yu course and I had tried all of the available solution which I could find, but only this one has helped to me:
while your project is opened:
press Product on the top pane
press Clean Build Folder
do not use hotkey combination - just press it with your mouse!
only this method help to me to get rid of this error.
I had the same problem. In my DataModel file, I changed entity name and the class name from "Category" to different one, such as "TodoListCategory." Then in my CategoryViewController, I changed all the Category objects to "TodoListCategory" and rebuild. It solved my problem.
After that, you might have error "Command CompileSwift failed with a nonzero exit code." Now, try to clean your project by using Shift + Command + K & Option + Shift + Command + K
If you are following Angela Yu's course, I found that by selecting Manual/None and then Class Definition for the Category Entity under Codegen, the classes are auto-generated.
Also run cmd + b afterwards.
Also in Angela's class. I found that by removing the core data models and reinitiating them as independent entities with no relationship, setting up the save and load functions, running the app, and then going back to link the relationship solved the issue. I think it has to do with saving the entities as NSManagedObject before being able to reference the attributes. I am guessing that without initiating them as an NSManagedObject the default type is Opaque Pointer. Best of luck!
I'm following the same lesson.
In my case was just an Xcode bug and "Category" was not recognized as a class.
I just close and re-open it and work fine.
Category did not provide name property
Change the 'categories' variable form 'var' to 'let'.
From,
var categories = [Category]()
to
let categories = [Category]()
Just re-build it and this is working.
If [Category]() is not recognized as a NSManagedOject, just put the term Category between two single reversed quotation marks inside the brackets.
link to example
While declaring a array of the type Category, do it like :
var categories = [[`Category`]]()
(if you have the name of the entity as "Category")
note: There is just a single back tick to the left of category.
Good day!
Please make sure you did not choose Opaque Pointer instead of your Class.
See below:
Screenshot
if you did, replace Category with 'Category'
We need to change the class Module to "Current Product Module" in inspector on the right
enter image description here

Hard Coding NSUserActivityTypes for Restoring Different Data Models

As of iOS 13, Apple recommends storing user state using an NSUserActivity object attached to a scene, so I've been trying to a) better understand how NSUserActivity works and b) implement that in my own code. In working through Apple's documentation, I came across this piece of code:
class var activityType: String {
let activityType = ""
// Load our activity type from our Info.plist.
if let activityTypes = Bundle.main.infoDictionary?["NSUserActivityTypes"] {
if let activityArray = activityTypes as? [String] {
return activityArray[0]
}
}
return activityType
}
I understand what this is doing (it looks at the Info.plist file for an entry called "NSUserActivityTypes", if it exists it tries to get the associated array of activityTypes, and then it reads the first item in the array), but what I don't understand is why. In particular, I don't understand why we're only reading the first item in activityArray. In this case we know the first (and only item) is "com.apple.apple-samplecode.StateRestoration.activity" because we have to manually create that plist entry. But I don't understand why we are hard coding looking at the first item of the array in order to get the activity type, because if we know we're just going to get back the String "com.apple.apple-samplecode.StateRestoration.activity", why not just write the code to be this:
class var activityType: String {
return "com.apple.apple-samplecode.StateRestoration.activity"
}
I've never worked with NSUserActivity before, and I understand that it can be (usually is?) used for things other than state preservation/restoration, so there could be many different kinds of useractivities that your app could support (handoff, Siri integration, etc.). So I would assume that we want our code to be as robust as possible in not making any assumptions about the kinds of NSUserActivity objects we might receive.
Maybe someone who has more experience with NSUserActivity can help explain the ways in which NSUserActivity might be handed to my app, and why we can hard code in the first element of an array, while in other places we want to check if a passed-in activity is the right kind of activity (even though we know our array of supported activities has only one kind of activity, so presumably there's only one kind of activity we'd receive in the first place?).
Also, this isn't unique to Apple's sample code... this blog post also takes a similar approach when reading the Info.plist file:
extension Bundle {
var activityType: String {
return Bundle.main.infoDictionary?["NSUserActivityTypes"].flatMap { ($0 as? [String])?.first } ?? ""
}
}
I do have the same doubt when reading the Apple's example of restoring user state using NSUserActivity, because in my past project I always have a Constant.swift to handle all the hardcode string (something like id, or key), for example:
Constants.swift
struct Constants {
static let userActivityTypeA = "com.apple.apple-samplecode.StateRestoration.activityA"
static let userActivityTypeB = "com.apple.apple-samplecode.StateRestoration.activityB"
}
I understand what this is doing (it looks at the Info.plist file for an entry called "NSUserActivityTypes", if it exists it tries to get the associated array of activityTypes, and then it reads the first item in the array), but what I don't understand is why.
In my opinion, it is not a must to follow the Apple's example (adding the activityType in the info.plist & read it using Bundle.main.infoDictionary). Apple just provide a way that is cleaner & can be easily identify what that String is, by providing a fixed key "NSUserActivityTypes" in the info.plist.
(Imagine someday your colleague pick up your project and he may have no idea what is that reverse domain string in the Constants.swift or wherever you placed it.)
why we can hard code in the first element of an array, while in other places we want to check if a passed-in activity is the right kind of activity (even though we know our array of supported activities has only one kind of activity, so presumably there's only one kind of activity we'd receive in the first place?).
It really depends on how many activityType your apps support, for example, you may want to add few more types in the future, like type A go to ViewController A, and type B will open an In-App browsers in your apps. If you know your apps only support one kind of activity, Yes you don't even need to check it, but in general, we always want to confirm what is received and give corresponding respond.
I think that both sample codes are just dummy ways to explain how states work.
There, they use a single restoration ID (com.apple.apple-samplecode.StateRestoration.activity) but your app may have more than that, so as you say, the sample code wouldn't make sense anymore.
Also note that even when using a single restoration ID you have all the NSUserActivity fields (including userInfo) to help you distinguish between states. Of course, it would be dirty to have very different states sharing the same restoration ID.

How can I read out the "glade ID" of a gtk3 object

In glade it is possible to set an unique ID to an object. In the code one can obtain a pointer to this object by searching for it's "glade ID" via gtk_builder_get_object().
However for my current use-case I just want to read out this ID from an GObject. What's the API to do so ?
You can't. The builder ID is stored in the builder internally, not in the GObject.
The reason for this is that IDs must be unique per builder, which would be impossible to enforce if you were able to get and set them via some GObject API.
You could use gtk_widget_get_name() to identify an object.
It is possible using Gtk.Buildable.get_name(object). This method will return the Glade object id.
This snippet will print all object ids in your Glade XML:
builder = Gtk.Builder()
builder.add_from_file("my-window.glade"))
for obj in builder.get_objects():
print(Gtk.Buildable.get_name(obj))
As stated by #ptomato it's seems not possible.
I found that in that line in the documentation:
All the fields in the GObject structure are private to the
implementation and should never be accessed directly.
But you can circumvent it because at one point in your code you were refering to it by the id that you typed in (or the code you wrote type in) so you just need to store it at that point. And link it somehow (with a variable or a data structure) to the name of the variable holding the object.

Working with Swift and Core Data

This is more of a generalized question as I have yet to write the code for the question I am asking. Before I get started writing the code I wanted to make sure I am on the right track and possibly getting suggestions for better ways to do what I want to do. Basically right now I have a core data model setup in a way that I think is correct for what I am trying to do and just need some guidance on a very specific part of the code but want to make sure overall I created it correctly.
The first part to the question is more of a clarification on how relationships work in core data. Right now I have 5 entities and to make sure I have the correct idea on how it works I will use a few examples to make sure I am on the right track.
So lets save I have an entity I called name. Within that Name entity that contains only a name attribute. Next I have an entity that has classes, that each have a boolean of true or false to determine which class it is. These 2 are related in a inverse relationship of Name entity having a to one relationship and the Classes having a to many relationship because multiple names can have multiple classes but each name can only have 1 class. If I am right on this one that means I full understand core data relationships!
Now the second part of the question is related to the booleans in the class. I have the Class entity which is like I said a boolean containing a true false set as default to false. When the user selects one of the class buttons before presenting the popover where they actually give the name of the class selected it saves the boolean to true then passes that data over to the popover Name view controller. I am very unsure as to how to do this as it isn't a widely asked question on here nor have I been able to find any info through researching. I am one of those people who needs to actually learn by clear examples....any help with this would be appreciated! Sorry I don't have any example code for this.
The first part seems correct. The ManagedObject of your Class CoreDataObject should have an NSSet property which will contain the names (as the Class can have multiple names)
For the second part, Core Data uses objects. When you 'get' the data from Core Data it will be a (probably extended) NSManagedObject (named Class in our case). You can send this object as a parameter just as you would do with any other object and use it as you would use any other object :-). For example looping over de NSSet Names
func iterateOverNames(someClass: Class) {
for name: Name in someClass.names {
// do stuff
}
}
You can check these links for more information:
https://realm.io/news/jesse-squires-core-data-swift/
https://developer.apple.com/library/ios/documentation/Cocoa/Reference/CoreDataFramework/Classes/NSManagedObject_Class/index.html