Say I have a class NamedShape defined like this:
class NamedShape {
var numberOfSides: Int = 0
var name: String
init(name: String) {
self.name = name
}
func simpleDescription() -> String {
return "A shape with \(numberOfSides) sides."
}
func containerFunc() -> Void{
println("strange world")
func subFunc() -> String {
return "sub function returns string"
}
println(subFunc())
}
}
I can initialize it like this:
let someNamedShape = NamedShape(name:"polynomial")
And invoke some method like this:
someNamedShape.containerFunc()
Now how can I invoke method subFunc within containerFunc on its object?
Compiler complains while trying this:
someNamedShape.containerFunc().subFunc()
It looks like it's not possible, unless you return the inner function from its containing function. Here's what the documentation says
Nested functions are hidden from the outside world by default, but can still be called and used by their enclosing function. An enclosing function can also return one of its nested functions to allow the nested function to be used in another scope.
This is how your code should look like in order to be able to call the subfunc
class NamedShape {
var numberOfSides: Int = 0
var name: String
init(name: String) {
self.name = name
}
func simpleDescription() -> String {
return "A shape with \(numberOfSides) sides."
}
func containerFunc() -> (() -> String) {
println("strange world")
func subFunc() -> String {
return "sub function returns string"
}
println(subFunc())
return subFunc
}
}
let someNamedShape = NamedShape(name:"polynomial")
let subfunc = someNamedShape.containerFunc()
subfunc()
Related
EDIT: (initial example was too simplified, so I rewrote the code to be more specific)
based on http://holko.pl/2016/01/05/typed-table-view-controller/
I am trying to see if it is possible to set the generic parameter of a type from a string..
Say we have this code
protocol Updatable
{
associatedtype ViewModel
func updateWith(viewModel: ViewModel)
}
class ToasterCell: UITableViewCell
{
var toast: String?
func updateWith(viewModel: String) {
toast = viewModel
//Additional config...
}
}
extension ToasterCell: Updatable
{
typealias ViewModel = String
}
class PriceCell: UITableViewCell
{
var tagPrice: Float?
func updateWith(viewModel: Float) {
tagPrice = viewModel
//Additional config
}
}
extension PriceCell: Updatable
{
typealias ViewModel = Float
}
protocol CellConfiguratorType {
var reuseIdentifier: String { get }
var cellClass: AnyClass { get }
func updateCell(_ cell: UITableViewCell)
}
class MyTypeTest<Cell> where Cell: Updatable , Cell: UITableViewCell
{
let viewModel: Cell.ViewModel
let reuseIdentifier: String = String(describing: Cell.self)
let cellClass: AnyClass = Cell.self
init(viewModel: Cell.ViewModel) {
self.viewModel = viewModel
}
func updateCell(_ cell: UITableViewCell)
{
if let c = cell as? Cell
{
c.updateWith(viewModel: viewModel)
}
}
}
extension MyTypeTest: CellConfiguratorType{
}
let myTT1 = MyTypeTest<PriceCell>(viewModel: 3.76)
let myTT2 = MyTypeTest<ToasterCell>(viewModel: "Carpe Diem")
let data = [myTT1, myTT2] as [CellConfiguratorType] // data for the tableView
//register Cell calss ...
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell
{
let cellConf = data[indexPath.row]
let cell = tableView.dequeueReusableCell(withIdentifier: cellConf.reuseIdentifier)
cellConf.updateCell(cell)
return cell
}
And we want to make it so that the type T is set from a string we get from a JSON response.
//Some JSON {"list":[{"k":"Price","v":368.0},"{"k":"ToasterCell","v":"YOLO"},"{"k":"Toaster","v":"Space"},{"k":"PriceCell","v":1999}]}
the JSON value does not map directly to any object/class, So I need to use that key "k" to know witch class to use.
I tried using the string from the "k" value to setup the cell configurator.
(short example)
//for now let skip any logic in decoding the value / viewModel.
let myTT1 = MyTypeTest<NSClassFromString(list.first.k + "Cell")>(viewModel: list.first.v as Any)
All I got was following errors:
Cannot assign value of type 'T' to type 'AnyClass' (aka 'AnyObject.Type')
Use of undeclared type 'myTypeOBJ'
Is there a way to do this via a string, or do I really need to create a huge "if-else" structure for whatever type I could get from my JSON responses?
EDIT:
I tried to add an init to the CellConfigurator with a param of type Cell so it can infer the Type from the param it self.
init(viewModel: Cell.ViewModel, inferUsing: Cell){....}
where I could attempt to use this (but is does not work as the PATs is getting in the way)
func getSafeBundelName() -> String
{
if let namespace = Bundle.main.infoDictionary!["CFBundleExecutable"] as? String
{
return namespace
}
return ""
}
let cellClass = NSClassFromString("\(getSafeBundelName()).PriceCell") as? UITableViewCell.Type
let cell = cellClass?.init()
let myTT1 = MyTypeTest(viewModel: list.first.v as Any, inferUsing: cell)
I get the error that the Cell type can not be infered. If I try to use the cellClass in the <>
ex: MyTypeTest<cellType>(viewModel: 3.76) all it gives me is that "cellClass" is not declared. Looks to me I am hitting a dead end where PATs become impossible to infer in any way that I can see. I find this limitation very very sad.
You can do this if you downcast the result from NSClassFromString to a type with a known initializer that you can call. If it will always be Toaster or a subclass then you can do:
if let myTypeOBJ = NSClassFromString("Toaster") as? Toaster.Type {
let test = myTypeTest(someOBJ: myTypeOBJ.init())
// test.someThing will be of type Toaster
}
In order for NSClassFromString to work you will also need to specify how you want the type name to be represented in objc, otherwise there will be some other stuff prepended to the type name:
#objc(Toaster)
class Toaster: NSObject
I'm trying to use an operator to parse a JSON into an object that conforms with the protocol mappable.
First I have a class called Map that is which it's function is store the current key it's being parsed and the complete JSON to parse and the current value to be stored
private class Map {
var json: [String : Any]?
var key: String!
convenience init(json: [String : Any]?) {
self.init()
self.json = json
}
public var currentValue: Any? {
get{
guard let key = key, let json = json else {
return nil
}
return json[key]
}
}
public subscript(key: String) -> Map {
// save key and value associated to it
self.key = key
return self
}
}
Then I have an operator that get the current value on the rhs based on the Map.Key and passes it to the lhs, and here lies the problem if the lhs is an Array with an object that follows the protocol Mappable, it should use the the operator recursively, until end parsing.
The problem is: the comparison lhs is Array always returns false, so I can't typecast it to do the necessary iteration to parse it. (commented lines).
Any ideas how to approach the problem?
infix operator <<< // JSON to object
private func <<< <T: Any>(lhs: inout T, rhs: Map) {
if let rhsArray = rhs.currentValue as? Array<Dictionary<String, Any>>{
print(type(of: lhs)) // <Array<(Book in *someHash*)>>
debugPrint(lhs is Array<Mappable>) // false
var rhsReturnArray: Array<Mappable> = []
for currentRHSValue in rhsArray {
// let object = T.Element.self.from(Map(json: currentRHSValue))
// rhsReturnArray.append(object)
}
// Do something
}
else if let value = rhs.currentValue as? T{
lhs = value
}
}
private class Autor: Mappable {
var books: [Book]?
func from(map: Map) -> Bool {
books <<< map["Books"]
return true
}
}
private class Book: Mappable {
var title: String?
var numberOfPages: Int?
func from(map: Map) -> Bool {
title <<< map["Title"]
numberOfPages <<< map["Number of Pages"]
return true
}
}
let someDictionary = ["Books" : [["Title": "Happy Potter", "Number of Pages": 420], ["Title": "Happy Potter2", "Number of Pages": 422]]]
private let autor = Autor()
autor.from(map: Map(json: someDictionary))
print(autor.books?.first)
And I can't use third part frameworks on this project.
Is there any difference in swift between function declaration:
func function(a: String) {
print(a);
}
function("test");
and closure assignment:
let closure = {
(a: String) in
print(a);
}
closure("test");
Is there any difference between those?
Named or anonymous
func function(a: String) {
print("\(a), name: \(__FUNCTION__)");
}
let closure = { (a: String) in
print("\(a), name: \(__FUNCTION__)");
}
Capture List
supported in closures only:
let obj = FooClass()
let closure = { [weak obj] in ... }
Curried function
supported in functions only:
func curriedFunc(x:Int)(y:Int) { ... }
let curried = curriedFunc(1)
curried(y:2)
Similar, but not exact the same with using closure:
let closure = { (x:Int) in { (y:Int) in ... }}
Generics
supported in functions only:
func function<T>(x:T) { ... }
Referenceability from its own initial declaration
supported in global functions only:
func recursive(var x:Int) -> Int {
...
return condition ? x : recursive(x)
}
You can do this using closure also:
var recursive:((Int) -> Int)!
recursive = { (var x) in
...
return condition ? x : recursive(x)
}
But this is not recommended because this causes strong reference cycles.
Overload
supported in functions only:
func function(a: String) { print("String: \(a)") }
func function(a: Float) { print("Float: \(a)") }
n.b. You can reference them as a closure like this:
let f:(Float) -> Void = function
Another difference: recursivity inside another function
Nested functions cannot be recursive:
func foo() {
func bar() { bar() } // does not compile
}
but closures inside other functions can be recursive:
func foo() {
var bar: (() -> ())!
bar = { bar() }
}
Let's say, for instance, you have the following code:
struct SomeStruct {
init (arg1: String, arg2: Int){
// Does Stuff with Variables
}
}
// Some Point Later
var str = "fasfsad"
var integer = 343
let smth = SomeStruct(arg1: str, arg2: integer)
Is it possible to modify the SomeStruct struct to make the following line of code legal?
let smth = SomeStruct(str, integer)
Yes, you can make the parameters anonymous by using an underscore for the external parameter name:
struct SomeStruct {
init (_ arg1: String, _ arg2: Int){
// Does Stuff with Variables
}
}
Here is how you can do this:
struct A {
var a: String
var b: String
init(_ a: String,_ b: String) {
self.a = a
self.b = b
}
}
var x = A("S", "B")
Ok. I have some trouble understanding what exactly is going on here with "MyPrinter"
Let me go step by step (please correct me if got something wrong)
1. The "Salute" structure is created
2. Call to "Greet" function
2.a Call to "CreatePrinterFunction" with the strgin "!!!". This function returns a "MyPrinter" (witch is a function that takes in a string and returns nothing)
3. the variables "message" and "defaultMessage" are set with the strings
Now here's the problem, I don't understand what exactly are those do("str") doing
package main
import "fmt"
type Salute struct {
name string
greeting string
}
type MyPrinter func (s string) ()
func Greet(salute Salute, do MyPrinter) {
message, defaultMessage := CreateMessage(salute.name, salute.greeting, "noName")
do(message)
do(defaultMessage)
}
func Print(s string) {
fmt.Print(s)
}
func PrintLine(s string) {
fmt.Println(s)
}
func CreatePrinterFunction(custom string) MyPrinter {
return func (s string) {
fmt.Println(s + custom)
}
}
func CreateMessage(name string, greeting ...string) (message string, defaultMessage string) {
message = name + " " + greeting[0]
defaultMessage = "hey " + name
return
}
func main() {
var s = Salute{"Joe", "hello"}
// Greet(s, PrintLine)
Greet(s, CreatePrinterFunction("!!!"))
}
CreatePrinterFunction returns a function literal:
return func (s string) {
fmt.Println(s + custom)
}
That function literal implements the MyPrinter interface, which is an interface implemented by any function that takes a string argument and returns nothing:
type MyPrinter func(s string)
(note that the MyPrinter definition in the provided snippet includes an extra () at the end which does nothing)
Then, that function created which implements the MyPrinter interface is passed as the do parameter of the Greet function:
func Greet(salute Salute, do MyPrinter) {
When code inside Greet runs do(message), the created function literal is called, which in its turn runs the equivalent of fmt.Println(message + custom).
It's a pretty convoluted way to do something simple. :-)