Is there a plural version of this command, so I can type in a list of children to add?
Kind of like:
addChildren(myNodeABC, myNodeXYZ, myNode123)
Write an extension to do it: (I wrote it in Swift 3 style, I do not have XCode available right now to verify this works)
extension SKNode
{
func add(children: SKNode...) {
for child in children{
addChild(child)
}
}
}
usage:
node.add(children:node1,node2,node3)
note:
... is called variadic parameters in case you want to know more about them: https://developer.apple.com/library/content/documentation/Swift/Conceptual/Swift_Programming_Language/Functions.html
If you want to use less lines, do:
extension SKNode
{
func add(children: SKNode...) {
children.forEach({addChild($0)});
}
}
Related
A function
func stepperValueChanged(_ myStepper: UIStepper) {
// do stuff with myStepper
}
A second function
func switchValueChanged(_ mySwitch: UISwitch) {
// do stuff with mySwitch
}
How do I create a third (alternative) function that can take either type?
func valueChanged(_ myComponent: /* ??? UIStepper or UISwitch, but nothing else ??? */) {
// do stuff with myComponent
}
I've explored using enums, typealiases and protocols; which resulted in lots of interesting Stackoverflow reads but no solution.
Examples that don't work
// ** DON'T COPY AND PASTE, DONT WORK!! ** //
typealias validUIComponent = UIStepper, UISwitch
// or
typealias validUIComponent = UIStepper & UISwitch
// or
enum UIComponent { case stepper(UIStepper); case _switch(UISwitch) }
// or
protocol UIComponent { }
extension UIStepper: UIComponent { }
extension UISwitch: UIComponent { }
// ** DON'T COPY AND PASTE, DONT WORK!! ** //
Why would I want to do this? Type checking. I don't want any other UI element to be passed to the function.
I realise I could if let/guard let or some other form of checking once in the function body and bail as required, but this would only catch run-time not compile-time type errors.
Also I realise I could use Any? or (better) UIControl and downcast as needed.
func valueChanged(_ myComponent: UIControl) {
// do stuff with
myComponent as! UIStepper
// do stuff with
myComponent as! UISwitch
}
But is there a syntactic/more expressive solution?
You mentioned enums, which sound like an excellent fit for this use case.
You can explicitly only require the types you expect, and nothing else.
By adding a property to the enum you can then expose a UIControl property to interact as needed, without the need for down-casting (which is generally considered to be an anti-pattern).
enum Component {
case `switch`(UISwitch)
case stepper(UIStepper)
var control: UIControl {
switch self {
case .switch(let comp):
return comp
case .stepper(let comp):
return comp
}
}
}
Then ask for a Component as a parameter to the function.
func controlValueChanged(_ myComponent: Component) {
// Now you can use them as a generic UIControl
let control = myComponent.control
// ...or different behaviours for each element
switch myComponent {
case .switch(let swit):
// use the `swit`
case .stepper(let step):
// use the `step`
}
}
Having said that, if the implementations for these types are totally different anyway, it may be more clear to define two separate functions.
I think you are over complicating things here and that there is no need to create any overhead by introducing a protocol or a new type (enum).
Instead I would handle this by using polymorphism and declaring multiple functions with the same signature.
func controlValueChanged(_ switch: UISwitch) {
// code…
}
func controlValueChanged(_ stepper: UIStepper) {
// code…
}
This will keep the calling code nice and tidy and the responsibility of each function clear.
If there are some common code between the two functions then extract that into a third common function
class MyClass {
func sampleFunction() { }
}
Suppose, I have a class and I want the method in it to be accessed/overriden by any of it's subclass but NOT by any other class in the same module. There is no such access modifiers available in swift which fulfills this requirement. In that case how can I achieve the same.
I think I know what you are trying to do. As Matt said, you need to mark it as file private.
If you have multiple classes in multiple files, then you need to do it through an extension. There is one caveat though, it has to be declared #objc.
//file X.swift
class X
{
}
//file Y.swift
class Y:X{
}
//file X-Extensions.swift
fileprivate extension X
{
#objc func doit(){}
}
fileprivate extension Y{
#objc override func doit() {
}
}
//file Z.swift
class Z{
let x = X()
func doit(){
x.doit() //syntax error, doit not found for instance x
}
}
Make it fileprivate and put all other classes that need to see it in the same file.
(You are trying to implement something like protected but Swift has no such access rule.)
I am trying to use factory pattern in swift, and give is my code
I have two protocols
protocol MyProtocol1{
func callLoginAPI()
}
protocol MyProtocol2{
func callPaymentAPI()
}
I have two structures which conform to these protocols
struct MyManager1: MyProtocol1{
func callLoginAPI()
{
debugPrint("Inisde--MyManager1 and ready to call an Login API")
}
}
struct MyManager2: MyProtocol2{
func callPaymentAPI()
{
debugPrint("Inisde--MyManager2 and ready to call Payment API")
}
}
I want to use the factory pattern to create the instance of Manager by passing the Protocol and returning a concrete object of the struct that conforms to that protocol
Example: ManagerFactory.create(MyProtocol1) --> should give me instance of MyManager1 and doing ManagerFactory.create(MyProtocol2) --> should give me instance of MyManager2
I assume that this may not work as I am asking for a concrete type at runtime, so I ended up doing something like this
protocol IManagerFactory{
func getMyManager1() -> MyProtocol1
func getMyManager2() -> MyProtocol2
}
struct ManagerFactory: IManagerFactory
{
func getMyManager1() -> MyProtocol1 {
return MyManager1()
}
func getMyManager2() -> MyProtocol2 {
return MyManager2()
}
}
But I am curious if what I am trying to do in the example is achievable, I am using swift 4.2.
I have seen other examples but all of them have the same protocol which they conform to like rectangle, square and circle conform to same protocol shape.
In my case, I have two separate protocols which do completely different things so is that even possible what I am trying to do in the example? OR the way I ended up with is the only way to go about it.
Please suggest what is the best possible approach.
First, I'm very suspicious of a "manager" that is a value (a struct) rather than an instance (a class). Do you really mean to be using structs and protocols here at all? Structs have no identity; two structs with the same properties must be completely interchangeable for each other, and things like that don't usually get named "manager."
What you're describing is certainly writeable. It's just kind of useless. Here's how you write it:
struct ManagerFactory {
static func create(_ type: MyProtocol1.Protocol) -> MyProtocol1 {
return MyManager1()
}
static func create(_ type: MyProtocol2.Protocol) -> MyProtocol2 {
return MyManager2()
}
}
let mgr1 = ManagerFactory.create(MyProtocol1.self)
let mgr2 = ManagerFactory.create(MyProtocol2.self)
But this is just an elaborate way to use method overloading to replace names.
What you seem to want is a single method, but what would its return type be? Even in C#, I don't think this is writable without adding nasty downcasts. (This is the point you and paulw11 discuss in the comments.) This isn't a limitation of Swift; it's a fundamental characteristic of types. Even in JavaScript, you'd need to know what you expect to get back or else you won't know what methods you can call on it (it's just you track that expectation in your head and docs rather than in the compiler and code).
You seem to have created a lot of protocols here, and I'm betting they mostly have exactly one implementation. That's bad Swift. Don't create protocols until you have a specific need for one. Don't create attractions for fun. They will burn you very quickly.
If your protocols really look like this, and you really have different implementations of these methods (i.e. don't do this if there is only one implementation of MyProtocol1 "just in case"), what you really want are functions:
struct API {
let login: () -> Void
let payment: () -> Void
}
let myAPI = API(login: myLoginFunction, payment: myPaymentFunction)
This will let you create different APIs if you need them. But again, only if you need this flexibility. If not, just use classes for instances, and structs for values, and avoid protocols until you have at least 2, and better 3, implementations in your program.
Suggest a swifty option:
protocol Manager {
// a generic protocol for all managers
}
protocol BadManager: Manager {
// properties and behaviour of BadManager
mutating func noBonus()
}
protocol GoodManager: Manager {
// properties and behaviour of GoodManager
mutating func bigBonus()
}
protocol ManagerFactory {
associatedtype Manager
mutating func createManager() -> Manager
}
struct gm: GoodManager {
mutating func bigBonus() {
print("tons of cookies & coffee")
}
}
struct bm: BadManager {
mutating func noBonus() {
print("all fired")
}
}
enum ManagerCreator<Manager>: ManagerFactory {
func createManager() -> Manager {
switch self {
case .goodManager:
return gm() as! Manager
case .badManager:
return bm() as! Manager
}
}
case goodManager
case badManager
}
TL;DR
How can I define optional methods in a swift protocol that accept custom typed parameters?
The case
I understand that the way to define optional methods in a swift protocol is using the #objc flag. Like so:
#objc protocol someSweetProtocol {
optional func doSomethingCool()
}
But when I wanted to use my custom type for the parameter, like so:
#objc protocol someSweetProtocol {
optional func doSomethingCool(🚶🏼: HSCoolPerson)
}
I got this error:
Which is not cool.
How can this problem be solved? Also can you explain why this is happening?
Addendum
This is how HSCoolPerson is defined:
class HSCoolPerson {
...
...
...
}
Nothing special there...
The problem is this:
class HSCoolPerson {
// ...
}
As the error message plainly tells you, that type, the class HSCoolPerson, is completely invisible to Objective-C. And a protocol optional method is an Objective-C language feature; Swift merely borrows it, as it were. (That's why you have to say #objc protocol to get this feature.) So any time you want to define a protocol optional method, you have to do it in a way that Objective-C can understand, because it is Objective-C that is going to do the work for you.
To expose this class to Objective-C, simply derive it from NSObject:
class HSCoolPerson : NSObject {
// ...
}
Problem solved.
Put the default implementations in an extension, like so:
class HSCoolPerson {}
protocol SomeSweetProtocol {
func doSomethingCool()
}
extension SomeSweetProtocol {
func doSomethingCool(🚶🏼: HSCoolPerson) {
// default implementation here
}
}
class SomeSweetClass: SomeSweetProtocol {
// no implementation of doSomethingCool(_:) here, and no errors
}
you can declare func like that in protocol
#objc optional func doSomethingCool(🚶🏼: HSCoolPerson)
I've got couple of classes that inherit from SKNode.
Both of them have a setup() method. They are pretty different from each other.
I've made a protocol like this:
protocol LevelProtocol {
func setup(level: Int)
}
and two of my classes look something like thes:
class Puzzle: SKNode, LevelProtocol {
func setup(level: Int) {do something}
class Action: SKNode, LevelProtocol {
func setup(level: Int) {do something}
And in my main class I need to use one of these classes in one variable.
How do I define this variable properly?
I've tried this:
var lvl: LevelProtocol
if myLevel > 5 {
lvl = Puzzle()
else {
lvl = Action()
}
lvl.setup(myLevel)
self.addChild(lvl)
But the compiler says that LevelProtocol is not convertible to SKNode
I know Im doing something wrong, just cannot understand what exactly.
I'm not really good in Swift but I think you could try self.addChild(lvl as SKNode)
Another solution:
Well, I think, then you need to redesign the inheritance. Try making class Level inheriting from SKNode and declare just one method setup there and leave its body empty. Then you create classes Puzzle and Action deriving from Level and having their own implementation of setup. Then your code is:
var lvl: Level
if myLevel > 5 {
lvl = Puzzle()
}
else {
lvl = Action()
}
lvl.setup(myLevel)
self.addChild(lvl)