Components of entities can be removed with:
entity.removeComponentForClass(SpriteComponent.self);
entity.removeComponentForClass(PhysicsComponent.self);
How are Entities removed from a SKScene?
There are plenty of tutorials about removing components, but I can't find anything explicit about removing entities. Is there something like removing a node?
node.removeFromParent();
I adapted this from Apple's DemoBots which contains samples for the RenderComponent and LayerConfiguration.
Array was extended using Swift solution here >> Array extension to remove object by value
var entities = [GKEntity]()
/// Stores a reference to the root nodes for each world layer in the scene.
var layerNodes = [LayerConfiguration:SKNode]()
func addEntity(entity: GKEntity)
{
self.entities.append(entity)
for componentSystem in self.componentSystems
{
componentSystem.addComponent(foundIn: entity)
}
// If the entity has a `RenderComponent`, add its node to the scene.
if let renderNode = entity.component(ofType: RenderComponent.self)?.node
{
self.addNode(node: renderNode, toLayer: .actors)
}
}
func removeEntity(entity:GKEntity)
{
for componentSystem in self.componentSystems
{
componentSystem.removeComponent(foundIn: entity)
}
if let renderNode = entity.component(ofType: RenderComponent.self)?.node
{
renderNode.removeFromParent()
}
self.entities.remove(entity)
}
func addNode(node: SKNode, toLayer layer: LayerConfiguration)
{
//
let layerNode = self.layerNodes[layer]!
layerNode.addChild(node)
}
Related
I have a strange problem:
I have a NSManagedObject called ItemTemplate. It has many child managed objects, e.g. CustomItemTemplate or SpecialItemTemplate.
Now I have a list viewController that is supposed to show these child managed objects. For example only "CustomItemTemplaze" or only "SpecialItemTemplate". I wrote this generic method to fetch all ItemTemplates and filter out the desired child-objects (I haven't found a better way yet).
private func loadTemplates<T: ItemTemplate>(ofType type: T.Type) -> [ModelObject] {
// ModelObject is just a model for my managed objects
var templates = [ModelObject]()
do {
let request: NSFetchRequest<ItemTemplate> = ItemTemplate.fetchRequest()
let result = try mainViewContext.fetch(request)
for item in result {
if item is T { // this is somehow always true
templates.append(item.modelObject) // add the converted item to the array
}
}
} catch let error as NSError {
print("Error: ", error.debugDescription)
}
return templates
}
I call it like this:
enum Category {
case custom
case special
public var templateClass: ItemTemplate.Type {
switch self {
case .custom:
return CustomItemTemplate.self
case .special:
return SpecialItemTemplate.self
}
}
}
loadTemplates(ofType: currentCategory.templateClass)
However, it's not filtering. if item is T seems to be true for every item. It thus returns every ItemTemplate, instead of only certain child objects.
Why is that? I can't explain it.
Thanks for any help!
Suppose you have some structs like:
struct Tattoo {
var imageTorso:UIImage?
var imageTorsoURL:URL?
var imageArms:UIImage?
var imageArmsURL:URL?
}
struct Player {
var name:String = ""
var tattoos:[Tattoo] = []
}
struct Team {
var name:String = ""
var players:[Player] = []
}
Now imagine that you have a method that was passed in a Team value with some players. You have to iterate thru the players and their tattoos, then download the images and add them into the images variables on the tattoos.
If you use a for in loop, then it won't work because each part of the loop gets a copy of the members of the array it's iterating over. I.e.:
for player in team.players {
for tattoo in player.tattoos {
if let url = tattoo.imageTorsoURL {
MyNetFramework.requestImage(from: url, completion: { image in
tattoo.imageTorso = image
}
}
}
}
After doing all the iterations and completion blocks, still, the original team variable is identical to what it was prior to doing any of this. Because each tattoo that the inner loop got was a copy of what is in the player's tattoos array.
Now I know you can use & to pass structs by reference in Swift but it's highly discouraged. As well I know you can use inout so they don't get copied when they come into functions, which is also discouraged.
I also know these could be made classes to avoid this behavior.
But supposing I don't have a choice in the matter -- they are structs -- it seems the only way to do this is something like:
for p in 0...team.players.count-1 {
for t in 0...team.players[p].tattoos.count-1 {
if let url = team.players[p].tattoos[t].imageTorsoURL {
MyNetFramework.requestImage(from: url, completion: { image in
team.players[p].tattoos[t].imageTorso = image
}
}
}
}
This feels ugly and awkward, but I don't know how else to get around this thing where for in loops give you a copy of the thing you're iterating through.
Can anyone enlighten me, or is this just how it is in Swift?
I think you already got the point: "When your requirement will be modifying the data, you better to use class instead."
Here is the question reference link for you. Why choose struct over class
struct is fast and you can use them to prevent creating a huge, messy class. struct provided the immutable feature and make us easier to follow the Function Programming
The most significant benefit of immutable data is free of race-condition and deadlocks. That because you only read the data and no worries about the problems caused by changing data.
However, to answer your question, I have few ways to solve it.
1. Renew whole data.
// First, we need to add constructors for creating instances more easier.
struct Tattoo {
var imageTorso:UIImage?
var imageTorsoURL:URL?
var imageArms:UIImage?
var imageArmsURL:URL?
init(imageTorso: UIImage? = nil, imageTorsoURL: URL? = nil, imageArms: UIImage? = nil, imageArmsURL: URL? = nil) {
self.imageTorso = imageTorso
self.imageTorsoURL = imageTorsoURL
self.imageArms = imageArms
self.imageArmsURL = imageArmsURL
}
}
struct Player {
var name:String
var tattoos:[Tattoo]
init() {
self.init(name: "", tattoos: [])
}
init(name: String, tattoos: [Tattoo]) {
self.name = name
self.tattoos = tattoos
}
}
struct Team {
var name:String
var players:[Player]
init() {
self.init(name: "", players: [])
}
init(name: String, players: [Player]) {
self.name = name
self.players = players
}
}
for player in team.players {
for tattoo in player.tattoos {
if let url = tattoo.imageTorsoURL {
// Catch old UIImage for matching which Tattoo need to be updated.
({ (needChangeImage: UIImage?) -> Void in
MyNetFramework.requestImage(from: url, completion: { image in
// Reconstruct whole team data structure.
let newPlayers = team.players.map { (player) -> Player in
let newTattos = player.tattoos.map { (tattoo) -> Tattoo in
if needChangeImage == tattoo.imageTorso {
return Tattoo(imageTorso: image)
} else {
return tattoo
}
}
return Player(name: player.name, tattoos: newTattos)
}
team = Team(name: team.name, players: newPlayers)
})
})(tattoo.imageTorso)
}
}
}
These codes are ugly, right? And there will not only be awful performance issue caused by going through whole data every network response; another problem is that might causes the retain cycle.
2. Don't hold UIImage in the data array.
Redesign your data structure, and use Kingfisher to help us download image synchronously.
Kingfisher is useful third party library. It provides clean and simple methods to use, and it's highly flexible.
let url = URL(string: "url_of_your_image")
imageView.kf.setImage(with: url)
However, I think the best way for you if you don't want to use Kingfisher is to change your declaration from struct to class.
Unfortunately that's the nature of struct and Swift doesn't offer a way for you modify the collection in-place while iterating over it. But can user enumerated() to get both the index and the element when iterating:
for (p, player) in team.players.enumerated() {
for (t, tattoo) in player.tattoos.enumerated() {
if let url = tattoo.imageTorsoURL {
MyNetFramework.requestImage(from: url, completion: { image in
team.players[p].tattoos[t].imageTorso = image
}
}
}
}
I've got a relationship where:
A Parent has many Children
ie:
class Factory: Object {
public let engines = List<Engine>()
}
class Engine:Object {
private let parents:LinkingObjects<Factory> = LinkingObjects(fromType: Factory.self, property: "engines")
var parent:Factory? {
return self.parents.first
}
}
I read the factories via JSON and create the children (Engine) manually in a for-loop, similar to this:
var engines:[Engine] = [Engine]()
for _ in stride(from:0, to: 3, by: 1) {
let engine: Engine = Engine.init()
engines.append(engine)
}
return engines
In my test I want to query the parent of a given engine to ensure that the parent is correct; or perhaps get a parent attribute.
However, whenever I try to grab an attribute via the parent its always empty;
for (_, element) in (factories.enumerated()) {
for (_, eng) in element.engines.enumerated() {
print (eng.parent ?? "N/A" as Any) // Always prints out N/A
}
}
Ideally I want to be able to access the parent's data; like the name of the parent, perhaps costs, etc.
I've tried resetting simulator and also deleting derived data; but regardless of what I do the results are always N/A or empty.
How can I query the given element and ensure that I can grab the parent data?
Many thanks
Turns out there were a number of issues that I had to do to resolve this.
I was using XCTest and Realm was causing issues where there were multiple targets.
Make all my model classes' public
Remove the models from the test target, this included a file where the JSON data was being loaded into memory
I had to write my data into Realm, which I had not done;
let realm = try! Realm()
try! realm.write {
for parent:EYLocomotive in objects {
for _ in stride(from:0, to: parent.qty, by: 1) {
let engine : EYEngine = EYEngine.init()
parent.engines.append(engine)
}
realm.add(parent)
}
}
I am trying to subclass GKGraphNode2D to also include different penalties for different terrains (in the costToNode method). When I create a new GKGraph with an array of my new subclass and call findPathFromNode on the GKGraph, it ignores my costToNode method entirely.
The code looks like:
public class PenaltyGraphNode: GKGraphNode2D {
public let penalty: Float
init(position: CGPoint, penalty: Float) {
self.penalty = penalty
let point = vector_float2(Float(position.x), Float(position.y))
super.init(point: point)
}
override public func costToNode(node: GKGraphNode) -> Float {
guard let penaltyNode = node as? PenaltyGraphNode else { return super.costToNode(node) }
return super.costToNode(node) * (1 + penaltyNode.penalty)
}
}
And where I am trying to use the GKGraph (node creation removed for brevity sake):
let penaltyNodes: [PenaltyGraphNode] = [penaltyNode1, penaltyNode2, ...]
let graph = GKGraph(nodes: penaltyNodes)
let path = graph.findPathFromNode(startNode, toNode: endNode) as? [PenaltyGraphNode]
The costToNode in my subclass is never getting called, I made sure that all of the nodes that I create in the graph and add to it later are all PenaltyGraphNodes, but it still won't call costToNode. When I print the graph's nodes property, it shows them as GKGraphNode2D objects only, not my subclass.
Am I missing something obvious here?
I have a Realm Object which has several relationships, anyone has a good code snippet that generalizes a copy method, to create a duplicate in the database.
In my case i just wanted to create an object and not persist it. so segiddins's solution didn't work for me.
Swift 3
To create a clone of user object in swift just use
let newUser = User(value: oldUser);
The new user object is not persisted.
You can use the following to create a shallow copy of your object, as long as it does not have a primary key:
realm.create(ObjectType.self, withValue: existingObject)
As of now, Dec 2020, there is no proper solution for this issue. We have many workarounds though.
Here is the one I have been using, and one with less limitations in my opinion.
Make your Realm Model Object classes conform to codable
class Dog: Object, Codable{
#objc dynamic var breed:String = "JustAnyDog"
}
Create this helper class
class RealmHelper {
//Used to expose generic
static func DetachedCopy<T:Codable>(of object:T) -> T?{
do{
let json = try JSONEncoder().encode(object)
return try JSONDecoder().decode(T.self, from: json)
}
catch let error{
print(error)
return nil
}
}
}
Call this method whenever you need detached / true deep copy of your Realm Object, like this:
//Suppose your Realm managed object: let dog:Dog = RealmDBService.shared.getFirstDog()
guard let detachedDog = RealmHelper.DetachedCopy(of: dog) else{
print("Could not detach Dog")
return
}
//Change/mutate object properties as you want
detachedDog.breed = "rottweiler"
As you can see we are piggy backing on Swift's JSONEncoder and JSONDecoder, using power of Codable, making true deep copy no matter how many nested objects are there under our realm object. Just make sure all your Realm Model Classes conform to Codable.
Though its NOT an ideal solution, but its one of the most effective workaround.
I had a similar issue and found a simple workaround to get a copy of a realm object. Basically you just need to make the object conform to the NSCopying protocol, something like:
import RealmSwift
import Realm
import ObjectMapper
class Original: Object, NSCopying{
dynamic var originalId = 0
dynamic var firstName = ""
dynamic var lastName = ""
override static func primaryKey() -> String? {
return "originalId"
}
init(originalId: Int, firstName: String, lastName: String){
super.init()
self.originalId = originalId
self.firstName = firstName
self.lastName = lastName
}
func copy(with zone: NSZone? = nil) -> Any {
let copy = Original(originalId: originalId, firstName: firstName, lastName: lastName)
return copy
}
}
then you just call the "copy()" method on the object:
class ViewController: UIViewController {
var original = Original()
override func viewDidLoad() {
super.viewDidLoad()
var myCopy = original.copy()
}
}
The nice thing about having a copy is that I can modify it without having to be in a realm write transaction. Useful when users are editing some data but didn't hit save yet or simply changed their mind.
Since this problem is still alive I post my solution which works but still needs to be improved.
I've created an extension of Object class that has this method duplicate that takes an object objOut and fills the flat properties by looking at self. When a non-flat property is found (aka a nested object) that one is skipped.
// Duplicate object with its flat properties
func duplicate(objOut: Object) -> Object {
// Mirror object type
let objectType: Mirror = Mirror(reflecting: self);
// Iterate on object properties
for child in objectType.children {
// Get label
let label = child.label!
// Handler for flat properties, skip complex objects
switch String(describing: type(of: child.value)) {
case "Double", "Int", "Int64", "String":
objOut.setValue(self.value(forKey: label)!, forKey: label)
break
default:
break
}
}
return objOut
}
Inside the Manager class for my Realms I have the method copyFromRealm() that I use to create my copies of objects.
To give you a practical example this is the structure of my Appointment class:
Appointment object
- flat properties
- one UpdateInfo object
- flat properties
- one AddressLocation object
- flat properties
- one Address object
- flat properties
- one Coordinates object
- flat properies
- a list of ExtraInfo
- each ExtraInfo object
- flat properties
This is how I've implemented the copyFromRealm() method:
// Creates copy out of realm
func copyFromRealm() -> Appointment {
// Duplicate base object properties
let cpAppointment = self.duplicate(objOut: Appointment()) as! Appointment
// Duplicate UIU object
cpAppointment.uiu = self.uiu?.duplicate(objOut: UpdateInfo()) as? UpdateInfo
// Duplicate AddressLocation object
let cpAddress = self.addressLocation?.address?.duplicate(objOut: Address()) as? Address
let cpCoordinates = self.addressLocation?.coordinates?.duplicate(objOut: Coordinates()) as? Coordinates
cpAppointment.addressLocation = self.addressLocation?.duplicate(objOut: AddressLocation()) as? AddressLocation
cpAppointment.addressLocation?.address = cpAddress
cpAppointment.addressLocation?.coordinates = cpCoordinates
// Duplicate each ExtraInfo
for other in self.others {
cpAppointment.others.append(other.duplicate(objOut: ExtraInfo()) as! ExtraInfo)
}
return cpAppointment
}
I wasn't able to find out a good and reasonable way to work with nested objects inside my duplicate() method. I thought of recursion but code complexity raised too much.
This is not optimal but works, if I'll find a way to manage also nested object I'll update this answer.
Swift 5+
Creates a Realm managed copy of an existing Realm managed object with ID
extension RLMObject {
func createManagedCopy(withID newID: String) -> RLMObject? {
let realmClass = type(of: self)
guard let realm = self.realm, let primaryKey = realmClass.primaryKey() else {
return nil
}
let shallowCopy = realmClass.init(value: self)
shallowCopy.setValue(newID, forKey: primaryKey)
do {
realm.beginWriteTransaction()
realm.add(shallowCopy)
try realm.commitWriteTransaction()
} catch {
return nil
}
return shallowCopy
}
}