Best way to assign the properties of one object to another (Trying to implement Copy function) in swift3 - swift3

I am trying to deep copy a Swift class instance. As copy and mutableCopy function are available only for NSObject class descendent, I am need to implement the copy function of my own for a Swift class object.
Here is what I did,
protocol Copying {
init(original: Self)
}
extension Copying {
func copy() -> Self {
return Self.init(original: self)
}
}
class A : Copying {
var name : String? = nil
var age : Int? = nil
var address : String? = nil
init(name : String) {
self.name = name
}
required init(original: A) {
//one way
self.name = original.name
self.age = original.age
self.address = original.address
//second way
let originalReflect = Mirror(reflecting: original)
let selfReflect = Mirror(reflecting: self)
for (_, originalAttr) in originalReflect.children.enumerated() {
for (_, attr) in selfReflect.children.enumerated() {
if originalAttr.label == attr.label {
//now I know the value of property and its value as well in original
//but how will I set it to self?
//If A was NSObject I could have said
self.setValue(originalAttr.value, forKey: originalAttr.label!)
}
}
}
}
}
Finally this is how I access the copy
let aInstance = A(name: "Sandeep")
let aCopy = aInstance.copy()
The first method shown in required init(original: A) works absolutely fine, but not scalable. In my project I have base class with 50 odd property and atlas 50 more subclasses. Now I cant write the required init(original: A) for each subclass and add self.property = original.property that looks very much dumb way to solve it.
Second method shows the usage of Mirror to iterate through all the properties of object and but gets stuck as there is no way to set the value of self as self.setValue(for key) is not available for swift classes.
Now I cant change the class type to NSObject for this benefit nor can I convert it to struct.
Reference :
Copy Protocol idea from : deep copy for array of objects in swift
Mirror idea from :
https://www.pluralsight.com/guides/microsoft-net/property-copying-between-two-objects-using-reflection
iterate over object class attributes in Swift
Any way to solve this? Suggestions would be really helpful.

Related

Roslyn / IPropertySymbol / arrary return type

I'm trying to return all the properties of a class, and the return type of each property using Roslyn (not reflection..)
I've gotten close, but then I hit a property that returns an array of strings (or perhaps an enumeration?) I'm fighting with how to find out the type within the array/collection...
public class msgClass // part of a larger class, and referenced as Roslyn Document
string[] Lines {get; set;} //property in larger class of properties
...
var DocumentsInProject = await roslynUtilities.GetMembers<BasePropertyDeclarationSyntax>(msgClass);
foreach (var itemClassProperty in DocumentsInProject)
{
var itemDeclaredSymbol = semanticModelOfDoc
.GetDeclaredSymbol(itemClassProperty) as IPropertySymbol;
if (itemDeclaredSymbol == null)
throw new Exception($"property: {itemClassProperty}");
var name = itemDeclaredSymbol.Name;
//what does it return?
string returnType = string.Empty;
if (itemDeclaredSymbol.Type.IsReferenceType)
{
var typeofKind = itemDeclaredSymbol.Type.TypeKind;
var typeincollection = itemDeclaredSymbol.Type.BaseType;
var containingType = itemDeclaredSymbol.Type.ContainingType.Name;
}
else
{
returnType = itemDeclaredSymbol.Type.Name;
}
}
If it isn't obvious this is isn't production code - I'm hacking as I'm new to Roslyn, and I'm working on building a Visual Studio add-in that is reviewing classes in a project.
You actually need to convert property type symbol to INamedTypeSymbol or to IArrayTypeSymbol. You can check that the type is generic [un]bound type by INamedTypeSymbol and try to figure out the generic type parameters. It will allow to you receive collection's element type if type not just generic type, but collection. Casting to IArrayTypeSymbol will allow to you get array's element type. So your code should look like this:
...
if (itemDeclaredSymbol.Type is INamedTypeSymbol namedType && namedType.IsGenericType)
{
// use namedType.TypeArguments if type is bound generic or namedType.TypeParameters if isn't
}
else if (itemDeclaredSymbol.Type is IArrayTypeSymbol arrayType)
{
// use arrayType.ElementType as you want
}
...

Swift3 - how to call class or struct functions by name

As I come from a JS background this is how I'd call a function by name stored in a variable:
var obj = {
foobar: function(param) {
// do something
}
};
var key = "foobar";
obj[key](123);
Now I would like to recreate this in Swift, for example:
struct obj = {
func foobar(param) {
// do something
}
}
let key:String = "foobar"
obj[key](123)
The above code unfortunately gives Type 'obj.Type' has no subscript members
Is there any way to call functions by names in a Struct, Class or a Dictionary (if it's even possible to store functions in Dicts?)
EDIT - MORE CONTEXT:
I have a user-supplied array of things say:
let arr = ["apples", "oranges", "pears"]
but this array can be as long as 20 items. Based on each item of the array I need to perform certain action. So I iterate over the array:
for (key, _) in arr {
if (key == "apples") {
handleApples()
}
if (key == "oranges") {
handleOranges()
}
// and so on...
}
Sure, I can have a function with a simple switch that would consist of 20 cases but that's far from ideal. What if my array grows to say 100 items?
I was hoping to achieve something similar to this:
for (key, _) in arr {
myClass[key]()
}
Is there any way to call functions by names in a Struct, Class or a Dictionary (if it's even possible to store functions in Dicts?)
Yes you can store a function into a dictionary
Let's define a function type
typealias FuncType = () -> ()
and 2 functions
func func0() {
print("Apples")
}
func func1() {
print("Oranges")
}
Now we can create a dictionary where the key is String and the value is FuncType
let dict : [String:FuncType] = [
"Apples" : func0,
"Oranges" : func1
]
And of course we can invoke a function stored into the dictionary
dict["Apples"]?() // prints "Apples"
I think this might be what you're looking for:
var obj: [String: Int] = {
// do something, like call foobar(param) that's defined outside of the variable
// or just manipulate data directly in here
return ["foobar": 123]
// or whatever dictionary you want that matches the type you defined for obj
}()
Kind of tough to give you a better answer without you posting the kind of output or behavior you're looking for.

How to mock NSDate in Swift?

I have to test some date calculation but to do so I need to mock NSDate() in Swift. Whole app is written in Swift and I'd like to write test in it as well.
I've tried method swizzling but it doesn't work (or I'm doing something wrong which is more likely).
extension NSDate {
func dateStub() -> NSDate {
println("swizzzzzle")
return NSDate(timeIntervalSince1970: 1429886412) // 24/04/2015 14:40:12
}
}
test:
func testCase() {
let original = class_getInstanceMethod(NSDate.self.dynamicType, "init")
let swizzled = class_getInstanceMethod(NSDate.self.dynamicType, "dateStub")
method_exchangeImplementations(original, swizzled)
let date = NSDate()
// ...
}
but date is always current date.
Disclaimer -- I'm new to Swift testing so this may be a horribly hacky solution, but I've been struggling with this, too, so hopefully this will help someone out.
I found this explanation to be a huge help.
I had to create a buffer class between NSDate and my code:
class DateHandler {
func currentDate() -> NSDate! {
return NSDate()
}
}
then used the buffer class in any code that used NSDate(), providing the default DateHandler() as an optional argument.
class UsesADate {
func fiveSecsFromNow(dateHandler: DateHandler = DateHandler()) -> NSDate! {
return dateHandler.currentDate().dateByAddingTimeInterval(5)
}
}
Then in the test create a mock that inherits from the original DateHandler(), and "inject" that into the code to be tested:
class programModelTests: XCTestCase {
override func setUp() {
super.setUp()
class MockDateHandler:DateHandler {
var mockedDate:NSDate! = // whatever date you want to mock
override func currentDate() -> NSDate! {
return mockedDate
}
}
}
override func tearDown() {
super.tearDown()
}
func testAddFiveSeconds() {
let mockDateHandler = MockDateHandler()
let newUsesADate = UsesADate()
let resultToTest = usesADate.fiveSecondsFromNow(dateHandler: mockDateHandler)
XCTAssertEqual(resultToTest, etc...)
}
}
If you want to swizzle it you need to swizzle a class that is internally used by NSDate and it is __NSPlaceholderDate. Use this only for testing since it is a private API.
func timeTravel(to date: NSDate, block: () -> Void) {
let customDateBlock: #convention(block) (AnyObject) -> NSDate = { _ in date }
let implementation = imp_implementationWithBlock(unsafeBitCast(customDateBlock, AnyObject.self))
let method = class_getInstanceMethod(NSClassFromString("__NSPlaceholderDate"), #selector(NSObject.init))
let oldImplementation = method_getImplementation(method)
method_setImplementation(method, implementation)
block()
method_setImplementation(method, oldImplementation)
}
And later you can use like this:
let date = NSDate(timeIntervalSince1970: 946684800) // 2000-01-01
timeTravel(to: date) {
print(NSDate()) // 2000-01-01
}
As others suggested I would rather recommend introducing a class Clock or similar that you can pass around and get a date from it and you can easily replace it with an alternative implementation in your tests.
Rather than use swizzling you should really design your system to support testing. If you do a lot of data processing then you should inject the appropriate date into the functions which use it. In this way your test injects the dates into these functions to test them and you have other tests which verify that the correct dates will be injected (when you stub the methods that use the dates) for various other situations.
Specifically for your swizzling problem, IIRC NSDate is a class cluster so the method you're replacing is unlikely to be called as a different class will be 'silently' created and returned.

Derived Class Method of Generic Class Template not being called

I have a generic class for making and processing JSON API requests. I pass in the TParam and TResult template parameters but when I use a derived type it's implementation is not being called.
Here is some code you can throw in a playground to illustrate:
import Cocoa
// Base class for parameters to POST to service
class APIParams {
func getData() -> Dictionary<String, AnyObject> {
return Dictionary<String, AnyObject>()
}
}
// Base class for parsing a JSON Response
class APIResult {
func parseData(data: AnyObject?) {
}
}
// Derived example for a login service
class DerivedAPIParams: APIParams {
var user = "some#one.com"
var pass = "secret"
// THIS METHOD IS CALLED CORRECTLY
override func getData() -> Dictionary<String, AnyObject> {
return [ "user": user, "pass": pass ]
}
}
// Derived example for parsing a login response
class DerivedAPIResult: APIResult {
var success = false
var token:String? = ""
// THIS METHOD IS NEVER CALLED
override func parseData(data: AnyObject?) {
/*
self.success = data!.valueForKey("success") as Bool
self.token = data!.valueForKey("token") as? String
*/
self.success = true
self.token = "1234"
}
}
class APIOperation<TParams: APIParams, TResult: APIResult> {
var url = "http://localhost:3000"
func request(params: TParams, done: (NSError?, TResult?) -> ()) {
let paramData = params.getData()
// ... snip making a request to website ...
let result = self.parseResult(nil)
done(nil, result)
}
func parseResult(data: AnyObject?) -> TResult {
var result = TResult.self()
// This should call the derived implementation if passed, right?
result.parseData(data)
return result
}
}
let derivedOp = APIOperation<DerivedAPIParams, DerivedAPIResult>()
let params = DerivedAPIParams()
derivedOp.request(params) {(error, result) in
if result? {
result!.success
}
}
The really weird thing is that only the DerivedAPIResult.parseData() is not called, whereas the DerivedAPIParams.getData() method is called. Any ideas why?
UPDATE: This defect is fixed with XCode 6.3 beta1 (Apple Swift version 1.2 (swiftlang-602.0.37.3 clang-602.0.37))
Added info for a workaround when using XCode 6.1 (Swift 1.1)
See these dev forum threads for details:
https://devforums.apple.com/thread/251920?tstart=30
https://devforums.apple.com/message/1058033#1058033
In a very similar code sample I was having the exact same issue. After waiting through beta after beta for a "fix", I did more digging and discovered that I can get the expect results by making the base class init() required.
By way of example, here is Matt Gibson's reduced example "fixed" by adding the proper init() to ApiResult
// Base class for parsing a JSON Response
class APIResult {
// adding required init() to base class yields the expected behavior
required init() {}
}
// Derived example for parsing a login response
class DerivedAPIResult: APIResult {
}
class APIOperation<TResult: APIResult> {
init() {
// EDIT: workaround for xcode 6.1, tricking the compiler to do what we want here
let tResultClass : TResult.Type = TResult.self
var test = tResultClass()
// should be able to just do, but it is broken and acknowledged as such by Apple
// var test = TResult()
println(test.self) // now shows that we get DerivedAPIResult
}
}
// Templated creation creates APIResult
let derivedOp = APIOperation<DerivedAPIResult>()
I do not know why this works. If I get time I will dig deeper, but my best guess is that for some reason having required init is causing different object allocation/construction code to be generated that forces proper set up of the vtable we are hoping for.
Looks possibly surprising, certainly. I've reduced your case to something rather simpler, which might help to figure out what's going on:
// Base class for parsing a JSON Response
class APIResult {
}
// Derived example for parsing a login response
class DerivedAPIResult: APIResult {
}
class APIOperation<TResult: APIResult> {
init() {
var test = TResult()
println(test.self) // Shows that we get APIResult, not DerivedAPIResult
}
}
// Templated creation creates APIResult
let derivedOp = APIOperation<DerivedAPIResult>()
...so it seems that creating a new instance of a templated class with a type constraint gives you an instance of the constraint class, rather than the derived class you use to instantiate the specific template instance.
Now, I'd say that the generics in Swift, looking through the Swift book, would probably prefer you not to create your own instances of derived template constraint classes within the template code, but instead just define places to hold instances that are then passed in. By which I mean that this works:
// Base class for parsing a JSON Response
class APIResult {
}
// Derived example for parsing a login response
class DerivedAPIResult: APIResult {
}
class APIOperation<T: APIResult> {
var instance: T
init(instance: T) {
self.instance = instance
println(instance.self) // As you'd expect, this is a DerivedAPIResult
}
}
let derivedOpWithPassedInstance = APIOperation<DerivedAPIResult>(instance: DerivedAPIResult())
...but I'm not clear whether what you're trying should technically be allowed or not.
My guess is that the way generics are implemented means that there's not enough type information when creating the template to create objects of the derived type from "nothing" within the template—so you'd have to create them in your code, which knows about the derived type it wants to use, and pass them in, to be held by templated constrained types.
parseData needs to be defined as a class func which creates an instance of itself, assigns whatever instance properties, and then returns that instance. Basically, it needs to be a factory method. Calling .self() on the type is just accessing the type as a value, not an instance. I'm surprised you don't get some kind of error calling an instance method on a type.

Spark List in Actionscript: Passing Layout & itemRenderer in construtctor

I am trying to create a generic List, where I can pass the layout & item renderer as parameters.
Since it is not possible to pass parameters to a MXML component's Constructor, I figured I should create my List in Actionscript.
I figured it would go something like this:
public class GenericList extends List {
public function GenericList(iR:ItemRenderer, ac:ArrayCollection, layout:LayoutBase) {
super();
this.dataProvider = ac;
this.layout = ... // don't even have access to this.layout
this.itemRenderer = iR // Cannot pass itemRender
}
I would prefer to have the List in MXML (because It will be easier using states later), but If I am forced to use pure Actionscript so I can instantiate it and pass in parameters, any help would go a long way.
You cannot set the itemRenderer property of a list must implement IClassFactory. So your assignment would look like this:
public function GenericList(cf:ClassFactory, ac:ArrayCollection, layout:LayoutBase) {
And the instantiation would be:
var myList:GenericList = new GenericList( new ClassFactory( com.company.renderers.MyItemRenderer, ....);
Regarding the layout:
List essentially wraps DataGroup, so it is the datagroup's layout that you need to access. However, dataGroup will not necessarily be instantiated yet. So you might have to create a private property that you then utilize in commitProperties.
private var _myLayout:LayoutBase; (populate in constructor via getter/setter)
protected var layoutInvalidated:Boolean;
public function set myLayout( layout:LayoutBase):void {
_myLayout = layout;
layoutInvalidated = true;
}
override protected function commitProperties():void {
super.commitProperties();
if( layoutInvalidated && dataGroup && dataGroup.layout ) {
layoutInvalidated = false;
dataGroup.layout = _myLayout;
}
}