What is the purpose of runtime mixins in groovy?
Mixins overall one of the ways to add functionallity to class without multiple inheritance issues. But what is its purpose in Groovy? Traits can do the same.
Annotation #Mixin is considered deprecated at all. Will runtime mixins have the same fate one day?
Runtime mixins give us the ability to add methods to existed classes at runtime. The important part of the answer is "existed" and "runtime".
So, you can easily add new methods to any 3rd party library at runtime.
Actually, recently I found a case where using mixins helped me a lot.
String.metaClass {
invokeMethod {
String name, args ->
System.out.println "[$name] invokation with $args"
}
}
class GroovyInterceptableWrapper
implements GroovyInterceptable {
}
String.mixin(GroovyInterceptableWrapper)
Though again if I used there trait instead of class and then invoked withTraits I would have achieved the same result.
In Objective-C, I created a very handy category (an extension, in Swift terms) of NSObject that added the ability to add arbitrary key/value pairs to any NSObject at runtime. It uses associated objects to attach a mutable dictionary to the object, and then provides get and set methods that get/set key/value pairs to/from that dictionary. It's only a few lines of code.
This makes it possible to attach arbitrary key/value pairs to ANY object at runtime, including objects created by the system. That's the key. There are cases where a system framework returns an object to you and you need to be able to attach a value to it.
This trick also makes it possible to create categories that have new instance variables. (Ok, they don't really, but for it does let you add new state variables to objects in a category.)
This isn't possible in Swift 1.2 because:
Swift doesn't have a base class for all objects like NSObject in
Objective-C. It uses AnyObject, which is a protocol.
Swift 1.2
doesn't allow extensions to protocols.
I had to give up on this under Swift 1.2.
But Swift 2 allows extensions to protocols. I thought "Great, now I can add my extension that lets me add key/value pairs to AnyObject!"
No joy.
When I try to create my extension for AnyObject:
extension AnyObject: AssociatedObjectProtocol
I get the error message
'AnyObject' Protocol cannot be extended
Arghh! So close, but nope. It seems like the language explicitly forbids extending AnyObject. Why is this, and is there any way around it?
I don't use my category on NSObject that often, but when I do, it's a lifesaver. I'd like to add it to my bag of tricks in Swift.
I could add it to NSObject just like I do in Objective-C, but that means it only works for objects that inherit from NSObject - making it not work for native Swift classes.
Unfortunately a workaround which does exactly the same as you want doesn't exist. So I would suggest to make a protocol which has an extension to add default implementations:
protocol A: AnyObject {}
// in Swift you would rather use this
protocol A: class {}
// add default implementations
extension A {
func aMethod() {
// code
}
}
// Example
class B: A {}
// use the method
B().aMethod()
This approach does not make all classes automatically conform to this protocol (but only classes can conform to it). So you have to make them conform yourself. Since you don't use this as much this would be a reasonable solution.
Along the lines of #Qbyte's answer, declaring that NSObject conforms to a protocol means that almost every class in the entire Cocoa/UIKit/Foundation universe will inherit that functionality:
protocol MyProtocol {
func doSomething()
}
extension MyProtocol {
func doSomething() {
print("This is me, doing something.")
}
}
extension NSObject: MyProtocol { }
You've just conformed 99% of Apple's framework classes to MyProtocol. You can make your own classes conform to MyProtocol by inheriting from NSObject or by simply conforming to it.
I feel like you had the answer in front of you. Extending NSObject works perfectly in Swift too. (Maybe not 6 years before tho 🥲)
extension NSObject { }
I am duplicating an existing Objective-C TV Show app to a new Swift version using Xcode 6.1 and am having some issues with CoreData.
I have created a model of 4 entities, created their NSManagedObject subclass (in Swift), and all files have the proper app targets set (for 'Compile Sources').
I am still getting this error whenever I try to insert a new entity:
CoreData: warning: Unable to load class named 'Shows' for entity
'Shows'. Class not found, using default NSManagedObject instead.
A few comments:
When saving to Core Data, I use the parent-child context way to allow background threading. I do this by setting up the ManagedObjectContext using:
lazy var managedObjectContext: NSManagedObjectContext? = {
// Returns the managed object context for the application (which is already bound to the persistent store coordinator for the application.) This property is optional since there are legitimate error conditions that could cause the creation of the context to fail.
let coordinator = self.persistentStoreCoordinator
if coordinator == nil {
return nil
}
var managedObjectContext = NSManagedObjectContext(concurrencyType: NSManagedObjectContextConcurrencyType.MainQueueConcurrencyType)
managedObjectContext.persistentStoreCoordinator = coordinator
return managedObjectContext
}()
and by saving data using:
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), { () -> Void in
var context = NSManagedObjectContext(concurrencyType: NSManagedObjectContextConcurrencyType.PrivateQueueConcurrencyType)
context.parentContext = self.managedObjectContext!
...rest of core data saving code here...
})
This warning is one of the quirks we have to deal with while the details of the Swift implementation are being ironed out. The warning occurs spuriously, i.e. your setup might work even if you do not follow the steps outlined below.
I have been able to get rid of it in most cases by making sure that the class is set correctly in the model editor. Unlike in many other SOF posts (including answers to this question), the suggestion to include the module name (like MyApp.Shows) has not helped me.
Make sure you check these three items:
1.
Version that works up to Xcode 7 beta 3
Notice that I corrected your entity name to the more appropriate singular.
Version that works for Swift 2.0 in Xcode 7.1
(Should work for Xcode 7 beta 4 and above)
You need to delete the text "Current Product Module" in Module!
2.
You should also follow the frequent recommendation to include
#objc(Show)
just above your class.
Note: If you are using Xcode 7 beta 4 or later, this step is optional.
3.
Also make sure to cast the created managed object to the proper class, as the default would be just NSManagedObject.
var newShow = NSEntityDescription.insertNewObjectForEntityForName("Show",
inManagedObjectContext: context) as Show
SWIFT 2 / XCODE 7 Update:
This issue (see my April 3 comment on this answer as well) is resolved in Swift 2 and XCode 7 beta release by Apple.
So you actually now do not need #objc(myEntity) in Swift as answered by Mundi or using
"MyAppName." before your Class name. It will stop working. So remove these, just put Class name in File and select Current Working Module as Module
and cheers!
But for those using #objc(myEntity) in Swift (like me), you can use this other solution instead which works smoothly.
In the xcdatamodel correct class in. It should look like this:
Here you go. Module.Class is the pattern for CoreData in Swift and XCode 6. You will also need the same procedure when using Custom Policy class in Model Policy or other CoreData stuff. A note: In image, The Name and Class should be Car and MyAppName.Car (or whatever the name of your entity). Here, User is a typo.
When using Xcode 7 and purely Swift, I actually had to remove #objc(MyClass) from my auto-generated NSManagedObject subclass (generated from Editor > Create NSManagedObject Subclass...).
In Xcode 7 beta 2 (and I believe 1), in the model configuration a new managed object of type File is set to the Module Current Product Module and the class of the object is shown in configuration as .File.
Deleting the module setting so it is blank, or removing the full stop so the class name in configuration is just File are equivalent actions, as each causes the other change. Saving this configuration will remove the error described.
In Xcode 6.1.1 you do not need to add the #objc attribute since the base entity is a subset of an objc class (NSManagedObject) (see Swift Type Compatibility. In CoreData the full Module.Class name is required. Be aware the Module name is what is set in Build Settings -> Packaging -> Product Module Name. By default this is set to $(PRODUCT_NAME:c99extidentifier) which will be the Target's name.
With xCode 7 and Swift 2.0 version, you don't need to add #objc(NameOfClass), just change the entity settings in "Show the Data Model Inspector" tab like below -
Name - "Your Entity Name"
Class - "Your Entity Name"
Module - "Current Product Module"
Code for Entity class file will be like (in my code Entity is Family) -
import UIKit
import CoreData
class Family: NSManagedObject {
#NSManaged var member : AnyObject
}
This example is working fine in my app with xCode 7.0 + swift 2.0
Do not forget to replace PRODUCT_MODULE_NAME with your product module name.
When a new entity is created, you need to go to the Data Model Inspector (last tab) and replace PRODUCT_MODULE_NAME with your module name, or it will result a class not found error when creating the persistent store coordinator.
You also need to use (at least with Xcode 6.3.2) Module.Class when performing your cast for example:
Assuming your module (i.e. product name) is Food and your class is Fruit
let myEntity = NSEntityDescription.entityForName("Fruit", inManagedObjectContext: managedContext)
let fruit = NSManagedObject(entity: myEntity!, insertIntoManagedObjectContext:managedContext) as! Food.Fruit
Recap:
Include module name when defining entity in Data Model Editor (Name: Fruit, Class: Food.Fruit)
When accessing the entity in code (i.e.SWIFT), cast it with Module.class (e.g. Food.Fruit)
I also encountered a similar problem, follow these steps to resolve:
The parent is NSManagedObject, not NSObject
The module of an
entity is default, not "Current Product Module"
Changing the Entity Class name in the Data Model editor to correspond to the class in question and adding #objc(NameOfClass) to file of each NSManagedObject right above the class declaration solved this problem for me during Unit Testing.
Most of these answers still seem to apply in Xcode 14. However, my Swift NSManagedObject subclass is included in a custom framework. So what worked for me is: In that Entity inspector, in that Module field (see screenshot in answer by khunsan), type in the name of your framework, for example, MyFramework.
What worked for me (Xcode 7.4, Swift) is changing the class name to <my actual class name>.<entity name>
in the Entity inspector, 'Class' box.
My initiator of the Managed object subclass, looks like this:
convenience init(<properties to init>) {
let entityDescr = NSEntityDescription.entityForName("<entity class name>", inManagedObjectContext: <managed context>)
self.init(entity: entityDescr!, insertIntoManagedObjectContext: <managed context>)}
//init properties here
For Xcode 11.5: if Codegen property is class Definition, and if you are not getting a suggestion for the entity you created in xcdatamodel. Try to quit Xcode and reopen your project again. It works for me. This answer is only if you are not getting suggestions but if your file doesn't get generated try any above answer.
I have an abstract java class which has a constructor and I'm extending it from a groovy class. (the idea is to keep the java class as a contract inside the app and load external groovy classes that implement certain constructors and methods)
How can I force in Groovy to implement an abstract super class's constructor?
Does Groovy allow to force the implementation of the abstract parent class's constructor?
The thing is that the Eclipse Groovy IDE is not forcing me to implement the constructor of the parent class in the subclass, I thougth Groovy would create it automatically and so that was the reason to not forcing it. However at run time when trying to get the constructor using java reflection fails it fails if I don't define the parent constructor in the subclass.
(I have 0 experience in Groovy)
It looks like an unchecked situation in the compiler. Upon decompiling, the extending class gets an empty constructor. Tests should get you covered, since this situation doesn't work in runtime.
I don't know of a way to use this class; i tried the ways i know:
abstract class AbstractClass {
String string
Integer integer
AbstractClass(String string, Integer integer) {
this.string = string
this.integer = integer
}
}
class ImplClass extends AbstractClass { }
// every constructor fails
abs1 = new ImplClass('a', 1)
abs2 = [string: 'b', integer: 2] as ImplClass
abs3 = new ImplClass(abs: 'c', a: 3)
abs4 = ImplClass [string:'d', integer:4]
Neither of them worked in runtime, but compiled fine ;-). The situation is more about compile error vs runtime error. Maybe filling a JIRA?
On the other way around, if you needed to inherit the constructors, you could go for #groovy.transfom.InheritConstructors in the extending class. This way you would have the constructors without needing to call super() explicitly.
How can we add some common constraints (i.e. maxLength, nullable) to a property of a Groovy class? I know we can do it at Grails domain class, but is it possible if that is a Groovy class (I use it as a DTO class for my Grails project)?
Thank you so much!
You can add constraints to command classes. If a command class is in the same .groovy file as a controller (in Groovy you can have more than one public class in each .groovy file), you don't need to do anything special for Grails to recongise it as a command class.
However, if your command class is somewhere else (e.g. under src/groovy), you need to annotate it with #Validateable and add the package name to the grails.validateable.packages parameter in Config.groovy. Here's an example of a command that's not in the same file as a controller
pacakge com.example.command
#Validateable
class Person {
Integer age
String name
static constraints = {
name(blank: false)
age(size 0..100)
}
}
Add the following to Config.groovy
grails.validateable.packages = ['com.example.command']
Command classes have a validate() method added by Grails. After this method is called, any errors will be available in the errors property (as per domain classes).
Using a grails Command Object is probably your best bet. It has constraints and validation, but no database backing. It's normally a value object that controllers use, but you could instantiate one outside of a controller without any problems.
Not sure if this is relevant to your use (I am not familiar with DTOs), but in the current version (2.3.8), you can also add Grails constraints to an abstract class, and they will be inherited by the domains that extend it. Your IDE might not like it though ;)