Custom Class Sprite Kit, don't work init by name for iOS 10 (Xcode 11.3.1) - sprite-kit

I have a parent class that is inherited from the standard SKScene, named as - SKSParent. It is created to perform the parent function of creating custom scenes by identifier. The problem is that when I launch the project on iOS 11 + everything works correctly, but when I launch on ios 10.3.1. My objects that I create by the scene ID do not accept the desired child class based on identifier. All objects are created as objects of the SKSParent class, regardless of their identifier and created .swift files.
Perhaps someone has encountered this behavior 😞
import SpriteKit
class Parent: SKScene {
}
class StoryScene: Parent {
}
class Story1: StoryScene {
}
class Story2: StoryScene {
}
class Story3: StoryScene {
}
Some condition for chose story(for example save current user progress to user default like story name)
Created some story with using for init by Name from super class like below:
let storyName = UserDefaults.standard.string(forKey: "current_user_story") ?? "Story1"
let currentStory = Parent(fileNamed: storyName)
/* some configurations with using object like Parent object */
/* presenting to user. */
In this case on iOS 10 current story is object of class 'Parant'...
In this case on iOS 11 and higher it's object of a specific type of Story(*)
The fact is that on ios 10 in such cases, objects load components from the .sks file but do not execute the life cycle methods of a particular class from the .swift file.

Related

How to use a AnimationPlaybackController at the Entity level

I am using realityKit and I want to stop and start a models animation depending on differing events like collisions and user interactions. I started by using a wrapper class to handle this logic, but this seemed to be cumbersome, and my app started crashing when I attempted to make more than one GameEntity.
Example:
class GameEntity: ObservableObject {
let model: ModelEntity
var currentMovementController: AnimationPlaybackController? = nil
// lots of other methods and properties ...
}
So now I am attempting to make a subclass of Entity where I will have an attribute for AnimationPlaybackController:
class ARXEntity: Entity {
var animationHandler: AnimationPlaybackController? = nil
// more methods ...
}
My question is: is it possible to use the AnimationPlaybackController on the entity level? If so, what is the right way to do it?

Core Data Background Thread Returning Inserted NSManagedObject

In my app I am using a NSPersistantContainer with two NSManagedObjectContexts (viewContext & background context). All my read operations are performed on view context, while all my write operations are performed on the background context (shown below).
Creating a new Animal class
class func new(_ eid: String) {
//Create Animal Entity
let container = CoreDataService.persistentContainer
container.performBackgroundTask { (context) in
let mo = Animal(context: context)
mo.eid = eid
mo.lastModified = Date()
mo.purchaseDate = Date()
mo.uuid = UUID()
do {
try context.save()
}
catch let error {
print(error)
}
}
}
The problem I am having is I need to return the newly created NSManagedObject (Animal) back to the manager class, where the Animal.new(eid) was called, to be used to show the object properties.
I have experimented with using a completion handler, but had issues returning the value, as was using a background NSManagedObject in the main thread.
Using possible new function
Animal.new(eid) { (animal) in
if let animal = animal {
}
What is the best approach for returning a newly created NSManagedObject, created in a background context?
What I do is to keep my CoreData managed objects within my CoreDataManager class, not exposing them out to the rest of my framework. So methods that are to create one or more managed objects would accept the data as an unmanaged object, and then create the managed object but not return it (as callers already have the unmanaged object). When fetching from the CoreDataManager, I'd create and populate a unmanaged object(s) and return that.
Now part of why I do this is because I'm using CoreData in a framework, such that I'd never want to hand a managed object to a client app of my framework. But it also solves other problems like the one you described.
(When I write apps, I use Realm, and those objects can go straight to app's UI classes because Realm is so much easier to, erm, manage. :)

How to do 'page' object design in XCUITest

I'm new to XCUITest. I would like to get some suggestions on how to design 'page' (actually more like screen) object XCUITest.
Is there any open-source project that give samples to reference?
I'm thinking to create a screen folder to put all the screen objects there to hold methods and locators for each screen. Create a test folder to put the actual test cases. And also create a lib folder to put the common methods there.
I was wondering 2 things: 1. How XCUITest reference the files in different folders, how can one test file import methods from 2 different screen files? 2. I'm also thinking to create a data file (acting like .json file). Should I set it as .swift file? and how to make my test call that?
many thanks!
You need not import files from different folders which reside in a same target. They can be used directly without importing.
Refer Reading in a JSON File Using Swift to read from json files.
For page object design
AppNameUITests/Screens/Screen1.swift
class Screen1 {
var app: XCUIApplication
init(app: XCUIApplication) {
self.app = app
}
var element1: XCUIElement {
return app.buttons.firstMatch
}
var element2: [XCUIElement] {
return app.textFields.allElementsBoundByIndex
}
func method1() -> Int {
element1.click()
return element2.count
}
}
AppNameUITests/Tests/TestSuite1.swift
class TestSuite1: XCTestCase {
override func setUp() {
// launch application and pre-conditions for the test case
}
override func tearDown() {
// clean up steps and terminate the application
}
func testMethod1() {
let app = XCUIApplication()
let screen1Obj = Screen1(app: app)
XCTAssertTrue(screen1Obj.method1() == 5, "Test failed.")
}
}

AS3 (animate cc 2018) Why does date keep coming back undefined?

I'm a beginner, so I'm sensing I'm making a simple mistake but I haven't been able to figure it out or find reference to a similar error on other forums.
My end goal is to create a graphic that changes colour depending on the time of day. Right now my issue is that I can not get a Date object to return anything for the life of me.
This is all I have put in a file called Main.as, that is called in one of the keyframes:
public class Main extends MovieClip {
var myDate1:Date = new Date();
trace(myDate1);
}
According to the API, if I don't define a specific date it should just take the current date from my system. But instead of doing the trace I keep getting "error 1120: Access of undefined property myDate1".
Why am I getting this error?
I should note I'm trying to make this for mobile so I've been testing the movie using AIR launcher.
Your script is wrong. You are not supposed to write code directly inside the class body. You need to define methods:
public class Main extends MovieClip
{
// Class constructor.
public function Main()
{
super();
// Output the current date.
trace(NOW);
}
// Static class property that always returns the current date.
static public function get NOW():Date
{
return new Date;
}
}

'An NSManagedObject of class 'className' must have a valid NSEntityDescription.' error

I've created simple entity 'CDWorkout' with one attribute 'name' inside CDModel.xcdatamodeld. Name of container in AppDelegate is also 'CDModel'. Class Codegen for 'CDWorkout' is Category/Extension. Here is code for CDWorkout class:
class CDWorkout: NSManagedObject {
class func createWorkout(workoutInfo : Workout, in context: NSManagedObjectContext) -> CDWorkout{
let workout = CDWorkout(context: context)
workout.name = "anyName"
return workout
}
}
the createWorkout function is called from another viewController with context argument as container.viewContext but it immediately crashes with message:
Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 'An NSManagedObject of class 'Workout_Generator.CDWorkout' must have a valid NSEntityDescription.'
What did i forget about?
The issue I had was that I needed to have the Class Module set to Current Product Module for my CDWorkout Entity.
In Xcode 10 there is a drop down in the Class section of the Data Model Inspector.
I had a silly minor issue that resulted in the same error. I was initializing NSPersistentContainer with the incorrect name.
It should have the same name as the source file with the extension .xcdatamodeld. e.g. modelFileName.xcdatamodelId
let persistentContainer = NSPersistentContainer(name: "modelFileName")
In my case the same problem was in #objc modifier in auto-generated header of data-class
#objc(CachedMovie)
public class CachedMovie: NSManagedObject {
I just removed #objc(CachedMovie) and it began to work
I came across this same error message when trying to insert/add a managed object from an extension (SiriKit). It seems to have been an issue with the namespace of the extension not matching the .xcdatamodeld file, because I was creating the entity description using MyClass.entity().
The combination that worked for me was:
#objc(MyClass) at the top of each NSManagedObject subclass
Entities in the data model use the default "Global namespace", not "Current Product Module"
Create the entity description using let entity = NSEntityDescription.entity(forEntityName: "MyClass", in: context)!
In AppDelegate check persistent container name.
let container = NSPersistentContainer(name: "CoreData")
If you trying to reach nonexistent Core Data, that may manifest as this error.
Name should be exact same as .xcdatamodeld object in navigation menu.
If you are using coreData from a static library make sure you specify the module aswell
This gives you the correct entity access MyStaticLibrary.MyManagedObject
So if your receiving warnings with this dot notation, its not looking in your module
One way this could happen is by trying to rename your entities. Make sure that these are the same!
I've got the same issue. In my case I used CoreData initialised and managed in framework wich I integrated with main app via SPM.
Solution
First, in the framework provide module name for entity by hand, by following steps:
open .xcdatamodel,
select Entity which you want to edit,
open Data Model Inspector (the 4th panel in right sidebar),
at section Class element Module by default presents Current Product Module -- enter here your Module name
Repeat these steps for each entity.
Second, in the framework override description for each NSManagedObject you use in project, f.ex. you have:
public class Person: NSManagedObject {
}
override there description with String without module name, like:
public class Person: NSManagedObject {
public override var description: String {
return "Person"
}
}
Code presented above will help if you use convenience initialiser for Person (like Person(context: Context)) which uses description to specify Person.entity().
For me, I forgot to add #objc(Reminder) in this below example. I wrote the NSManagedObject class programmatically.
#objc(Reminder)
public class Reminder: NSManagedObject {
}
I encountered this issue using Swift Package Manager to import a Swift Package that had a model file included as a resource. In my case setting the Module of my entity to Current Production Module produced an incorrect value in the model file. When I used the debugger to print the model after loading the persistent container the fully qualified class name was something like Module_Module.Class instead of the expected Module.Class. I had to manually type the module name instead of using Current Production Module to resolve the issue.
in your file modeldataClass
probably name of Class is incorrect cause before you change name something in your name class
The mistake I made was to change the name of the entity and the generated "NSManagedObject Subclass" and not updating the name of the class. How to fix:
open .xcdatamodeld
click on the entity
open the right panel
Go to Data Model Inspector
Change the name of the Class text field
What fixed it for me was that I had an empty space in the name and didn't notice because of a line break. Removing it fixed the problem..
It was:
container = `NSPersistentContainer(name: "ContainerName ")`
Instead of:
container = NSPersistentContainer(name: "ContainerName")
I had similar issue in CoreData stack with NSManagedObjectModel made from Swift code. The issue was in wrong value for NSEntityDescription.managedObjectClassName attribute. The Swift module prefix was missed.
Correct setup:
let entity = NSEntityDescription()
entity.name = PostEntity.entityName // `PostEntity`
entity.managedObjectClassName = PostEntity.entityClassName // `MyFrameworkName.PostEntity`
entity.properties = [....]
Where: entityName and entityClassName defined like this.
extension NSManagedObject {
public static var entityName: String {
let className = NSStringFromClass(self) // As alternative can be used `self.description()` or `String(describing: self)`
let entityName = className.components(separatedBy: ".").last!
return entityName
}
public static var entityClassName: String {
let className = NSStringFromClass(self)
return className
}
}
I was trying out adding CoreData to existing project and I renamed things a lot. I ended up with multiple .xcdatamodeld without knowing it. The solution was removing .xcdatamodeld and generated NSManagerObject and recreating it again.
it easy to answer to this question. without removed
#objc(Workout)
the solution is on documentary Core Data Programming on "Entity Name and Class Name".
here in your Xcode before doing (Editor -> Create NSManagedObject SubClass)
must change your class Name of Entities to add "MO", CoreData can differentiate between class Name and Entitie Name. and the
#objc(Workout)
will not be created, give us this one:
class CDWorkoutMO: NSManagedObject {
class func createWorkout(workoutInfo : Workout, in context: NSManagedObjectContext) -> CDWorkoutMO {
let workout = CDWorkoutMO(context: context)
workout.name = "anyName"
return workout
}
}
like I do on my Xcode
For SwiftUI you need to also update this method from SceneDelegate:
func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
//This gets the context from AppDelegate and sets is as moc environment variable
let context = (UIApplication.shared.delegate as! AppDelegate).persistentContainer.viewContext
let contentView = ContentView().environment(\.managedObjectContext, context)
//...
}
In my case, I had my Core Data model inside a Swift Package and had to follow this amazing guide and finally this is what did it:
I opened the model and selected the entity and in the right panel I selected the Data Model Inspector and in the Class panel, I manually entered the Module’s name i.e. the Swift Package name.
For me this worked,
Adding
#objc('YourEntityClassName')
above the class declaration in 'YourEntityClassName+CoreDataClass' file.
Note: I am using this in an SPM package.