Is there any dump() like function returns a string? - ios

I like Swift's dump() function like this,
class MyClass {
let a = "Hello"
let b = "Bye!"
init() {}
}
let myClass = MyClass()
dump(myClass) // Printed out these lines to Xcode's console
/*
▿ MyClass #0
- a: Hello
- b: Bye!
*/
But dump() doesn't return a string. It just prints out to the console, and returns 1st parameter itself.
public func dump<T>(x: T, name: String? = default, indent: Int = default, maxDepth: Int = default, maxItems: Int = default) -> T
Is there any dump() like function returns a string?

From: https://github.com/apple/swift/blob/master/stdlib/public/core/OutputStream.swift
/// You can send the output of the standard library's `print(_:to:)` and
/// `dump(_:to:)` functions to an instance of a type that conforms to the
/// `TextOutputStream` protocol instead of to standard output. Swift's
/// `String` type conforms to `TextOutputStream` already, so you can capture
/// the output from `print(_:to:)` and `dump(_:to:)` in a string instead of
/// logging it to standard output.
Example:
let myClass = MyClass()
var myClassDumped = String()
dump(myClass, to: &myClassDumped)
// myClassDumped now contains the desired content. Nothing is printed to STDOUT.

try this if you want :
let myClass = MyClass()
print("----> \(String(MyClass))")
print("----> \(String(dump(myClass))) ")
UPDATE:
you can combine the string you like use Mirror:
let myClass = MyClass()
let mirror = Mirror(reflecting: myClass)
var string = String(myClass) + "\n"
for case let (label?, value) in mirror.children {
string += " - \(label): \(value)\n"
}
print(string)
hope it be helpful :-)

Related

SwiftUI Can't Pass String to KeyPath

I have an app that references a large dataset that I load from an external public
site as a comma separated value file. I parse the data to a an array of a model called
WaterPointModel. An abbreviated version is:
struct WaterPointModel: Identifiable {
let id = UUID()
let STATE: String
let COUNTY: String
let AQWFrTo: Double
let AQWGWSa: Double
let AQWGWTo: Double
//many more
}
I then want to summarize(reduce) the data. My function for this is:
func sumOnAttributeUSList(sumField: KeyPath<WaterPointModel,Double>) -> Double {
return dataStore.waterPointModels.map({ $0[keyPath:sumField] }).reduce(0, +)
}
Next I want to call this to build a report:
let aqWFrTo = sumOnAttributeUSList(sumField: \.AQWFrTo)
This all works. However there are other reports where I need to pass a string to
create that keypath. Say I have a lookup table where I lookup "abc" and get "AQWFrTo". I
would like to do something like this in a loop:
let abc = "AQWFrTo"
let aqWFrTo = sumOnAttributeUSList(sumField: \WaterPointModel.abc)
I have not been able to make any version of this work. Any guidance would be appreciated.
Xcode 13.3.1, iOS 15.4
A simple approach is this:
func toKeypath(_ str: String) -> KeyPath<WaterPointModel,Double>? { // <-- with or without optional
switch str {
case "AQWFrTo": return \.AQWFrTo
case "AQWGWSa": return \.AQWGWSa
case "AQWGWTo": return \.AQWGWTo
// ...
default: return nil // <-- or a default Keypath
}
}
let aqWFrTo = sumOnAttributeUSList(sumField: toKeypath("AQWFrTo"))

user generic function to determine the instance type in swift

I have three classes that conforms to same object type (protocol).
class Bicycle: Vehicle {}
class Car : Vehicle {}
class Truck: Vehicle {}
class Bus : Vehicle {}
I have an array that holds objects of the above classes like
let vehicle1 = Car()
let vehicle2 = Bicycle()
let vehicle3 = Truck()
let vehicle4 = Car()
let vehicle5 = Bus()
let listOfVehicles = [vehicle1, vehicle2, vehicle3, vehicle4, vehicle5]
Now I need an array which will tell me the index of the parameter that passed.
func getFirstIndex<T: Vehicle>(for targetObject: T) -> Int {
guard let index = listOfVehicles.firstIndex(where: { $0 is targetObject.Type })
else {
return -1
}
return index
}
If I call getFirstIndex(for: vehicle3), I need to get 2 and
If I call getFirstIndex(for: vehicle4), I need to get 0,
because vehicle4's type and vehicle1's type is same which is Car.
But I am getting compile-error "Type of expression is ambiguous without more context".
Does anyone have any clue.
Just replace targetObject.Type with T

Have a variable with multiple types in Swift

I would like to have a variable, which can have multiple types (only ones, I defined), like:
var example: String, Int = 0
example = "hi"
This variable should be able to hold only values of type Int and String.
Is this possible?
Thanks for your help ;)
An “enumeration with associated value” might be what you are looking for:
enum StringOrInt {
case string(String)
case int(Int)
}
You can either assign a string or an integer:
var value: StringOrInt
value = .string("Hello")
// ...
value = .int(123)
Retrieving the contents is done with a switch-statement:
switch value {
case .string(let s): print("String:", s)
case .int(let n): print("Int:", n)
}
If you declare conformance to the Equatable protocol then
you can also check values for equality:
enum StringOrInt: Equatable {
case string(String)
case int(Int)
}
let v = StringOrInt.string("Hi")
let w = StringOrInt.int(0)
if v == w { ... }
Here is how you can achieve it. Works exactly how you'd expect.
protocol StringOrInt { }
extension Int: StringOrInt { }
extension String: StringOrInt { }
var a: StringOrInt = "10"
a = 10 //> 10
a = "q" //> "q"
a = 0.8 //> Error
NB! I would not suggest you to use it in production code. It might be confusing for your teammates.
UPD: as #Martin R mentioned: Note that this restricts the possible types only “by convention.” Any module (or source file) can add a extension MyType: StringOrInt { } conformance.
No, this is not possible for classes, structs, etc.
But it is possible for protocols.
You can this:
protocol Walker {
func go()
}
protocol Sleeper {
func sleep()
}
var ab = Walker & Sleeper
or even
struct Person {
var name: String
}
var ab = Person & Walker & Sleeper
But I don't recomment use this way.
More useful this:
struct Person: Walker, Sleeper {
/// code
}
var ab = Person
You can use Tuple.
Example:
let example: (String, Int) = ("hi", 0)
And access each data by index:
let stringFromExampleTuple = example.0 // "hi"
let intFromtExampleTuple = example.1 // 0

Passing custom swift object to javascript methods as input

I'm using javascriptcore framework to interact with the JS file functions.
I have the object in the following type
class Test: NSObject {
var testId: NSNumber?
var testIndex: Int?
var testDate: NSDate?
var title: String?
var status: String?
}
I'm creating the array of object and passing as input to javascript method like below
var testArray = [Test]()
for i in 0 ..< 4 {
let test = Test()
test.testId = i * 3
test.testIndex = i
test.testDate = NSDate()
test.title = "Test \(i)"
test.status = "waiting"
testArray.append(test)
}
I have to pass this array to method to JS, Please let me know how to pass it.
You should be able to pass the attributes to JS as described here:
http://nshipster.com/javascriptcore/
The blocks-way
Couldn't test the code without Mac now, but is maybe working:
let testArrayCount: #convention(block) Void -> String = {
return testArray.count
}
let transferTest: #convention(block) String -> (String, String, String, String, String) = {
i in
return ( String(testArray[i].0),String(testArray[i].1),String(testArray[i].2),testArray[i].3,testArray[i].4 )
}
context.setObject(unsafeBitCast(testArrayCount, AnyObject.self), forKeyedSubscript: "testArrayCount")
context.setObject(unsafeBitCast(transferTest, AnyObject.self), forKeyedSubscript: "transferTest")
Now you can read the array in your JS-code (this is Pseudocode now):
var jsTestArray;
for ( i=0, i<testArrayCount(), i++ ) {
jsTestArray.append( transferTest(i) );
}
After loading object after object into your Javascript, you should be able to work with the array. If you don't want to work with strings only you may have to cast the things back (but as JS noob I don't wheather it's necessary)
Using JSExport Protocol
You can try it also the other way, described on http://nshipster.com/javascriptcore/ .
Hope, this answered your question?

How to Deal with Default Initializer when variable are not initialized Using Struct

I'm using swift struct and trying to use its default initializer when my struct variables are not initialize, I try both non-optional and optional variables but in its only showing "memberwise Initializer".
below is example with optional variables
struct myFirstStruct {
var value1:String?
var value2:String?
}
below is example with non-optional variables
struct myFirstStruct {
var value1:String
var value2:String
}
and it only gives
myFirstStruct(value1: <#String?#>, value2: <#String?#>)
and i want to use myFirstStruct()
help me. :)
Xcode is only showing you the 'member-wise' initialiser, but it's perfectly valid to use myFirstStruct(), passing no arguments, because all your variables have default values.
struct myFirstStruct {
var value1:String?
var value2:String = "InitialString"
}
let s1 = myFirstStruct()
// value1 = nil, value2 = "InitialString"
let s2 = myFirstStruct(value1: "Hello", value2: "World")
// value1 = "Hello", value2 = "World"
Need to set default value.
struct myFirstStruct {
var value1:String? = nil
var value2:String? = nil
}
let object = myFirstStruct()

Resources