AnyObject vs. Struct (Any) - ios

I would like to create a method like this for my projects:
func print(obj: AnyObject) {
if let rect = obj as? CGRect {
println(NSStringFromCGRect(rect))
}
else if let size = obj as? CGSize {
println(NSStringFromCGSize(size))
}
//...
}
But I can't because CGRect and CGSize are structs and do not conform to the AnyObject protocol. So, any ideas on how this could be done?

Use Any instead of AnyObject.
Swift provides two special type aliases for working with non-specific
types:
• AnyObject can represent an instance of any class type.
• Any can represent an instance of any type at all, including function types.
The Swift Programming Language

#nkukushkin's answer is correct, however, if what you want is a function that behaves differently depending on whether it’s passed a CGRect or a CGStruct, you are better off with overloading:
func print(rect: CGRect) {
println(NSStringFromCGRect(rect))
}
func print(size: CGSize) {
println(NSStringFromCGSize(size))
}
In comparison, the Any will be both inefficient (converting your structs to Any and back, could have a big impact if you do this a lot in a tight loop), and non-typesafe (you can pass anything into that function, and it will only fail at runtime).
If your intention is to coerce both types into a common type and then do the same operation on it, you can create a 3rd overload that takes that type, and have the other two call it.

Just discovered a much better method of doing this. Swift has a method called dump, and it works with a lot of kinds of data.
For example:
dump(CGRectMake(0, 5, 30, 60))
Will print:
{x 0 y 5 w 30 h 60}

If you just need to print a CGRect or CGSize, you could use:
println(rect)
or
println(size)
You left a '...' at the end of your function so I assume there are more types that you need to print. To do that you need to make those types conform to the Printable protocol (unless they already do). Here's an example of how -
class Car {
var mileage = 0
}
extension Car : Printable {
var description: String {
return "A car that has travelled \(mileage) miles."
}
}
The you can use:
let myCar = Car()
println(myCar)
Also, you may want to change the format of the way a type is currently printed. For example, if you wanted println(aRect) in the same format as returned by NSStringFromCGRect you could use the extension:
extension CGRect : Printable {
public var description: String {
return "{\(origin.x), \(origin.y)}, {\(size.width), \(size.height)}"
}
}

Related

Swift generic class, inheritance and covariance

I'm faced with the problem of using generic class and inheritance.
Brief description of the problem:
I have a base class called BookPageDataSource and two inherited classes (ReadingBookPageDataSource and StarsBookPageDataSource) with different implementations.
Also, I have a generic class BookPageViewController that contains the generic parameter of this data source and two inherited classes (ReadingBookPageViewController and StarsBookPageViewController) from this class.
I need to write a method the return parameter of which is BookPageViewController<DataSource>.
// Data Sources
class BookPageDataSource { }
class ReadingBookPageDataSource: BookPageDataSource { }
class StarsBookPageDataSource: BookPageDataSource { }
// Controllers
class BookPageViewController<DataSource: BookPageDataSource>: UIViewController {
let dataSource: DataSource
init(dataSource: DataSource) {
self.dataSource = dataSource
super.init(nibName: nil, bundle: nil)
}
required init?(coder aDecoder: NSCoder) {
return nil
}
}
final class ReadingBookPageViewController: BookPageViewController<ReadingBookPageDataSource> { }
final class StarsBookPageViewController: BookPageViewController<StarsBookPageDataSource> { }
// Communication
class Pager {
func currentPageController<DataSource>(at index: Int) -> BookPageViewController<DataSource> {
// for example
if index == 0 {
// How to remove the cast from the line below?
return readingPageController() as! BookPageViewController<DataSource>
}
return starsPageController() as! BookPageViewController<DataSource>
}
private func readingPageController() -> ReadingBookPageViewController {
return ReadingBookPageViewController(dataSource: ReadingBookPageDataSource())
}
private func starsPageController() -> StarsBookPageViewController {
return StarsBookPageViewController(dataSource: StarsBookPageDataSource())
}
}
The method currentPageController always crashes, because the DataSource is always equals to BookPageDataSource, not to ReadingBookPageDataSource or StarsBookPageDataSource.
Conceptual Discussion
Your concept for the architecture is flawed and this is leading to your issue.
Simple Generics Example
Here's a very simple example of a generic function, which just returns the value you give it:
func echo <T> (_ value: T) -> T { return value }
Because this function is generic, there is ambiguity about the type that it uses. What is T? Swift is a type-safe language, which means that ultimately there is not allowed to be any ambiguity about type whatsoever. So why is this echo function allowed? The answer is that when I actually use this function somewhere, the ambiguity about the type will be removed. For example:
let myValue = echo(7) // myValue is now of type Int and has the value 7
In the act of using this generic function I have removed the ambiguity by passing it an Int, and therefore the compiler has no uncertainty about the types involved.
Your Function
func currentPageController <DataSource> (at index: Int) -> BookPageViewController<DataSource>
Your function only uses the generic parameter DataSource in the return type, not in the input - how is the compiler supposed figure out what DataSource is?* I assume this is how you imagined using your function:
let pager = Pager()
let controller = pager.currentPageController(at: 0)
But now, what is the type of controller? What can you expect to be able to do with it? It seems that you're hoping that controller will take on the correct type based on the value that you pass in (0), but this is not how it works. The generic parameter is determined based on the type of the input, not the value of the input. You're hoping that passing in 0 will yield one return type, while 1 will yield a different one - but this is forbidden in Swift. Both 0 and 1 are of type Int, and the type is all that can matter.
As is usually the case with Swift, it is not the language/compiler that is preventing you from doing something. It is that you haven't yet logically formulated what is even is that you want, and the compiler is just informing you of the fact that what you've written so far doesn't make sense.
Solutions
Let's move on to giving you a solution though.
UIViewController Functionality
Presumably there is something that you wanted to use controller for. What is it that you actually need? If you just want to push it onto a navigation controller then you don't need it to be a BookPageViewController. You only need it to be a UIViewController to use that functionality, so your function can become this:
func currentPageController (at index: Int) -> UIViewController {
if index == 0 {
return readingPageController()
}
return starsPageController()
}
And you can push the controller that it returns onto a navigation stack.
Custom Functionality (Non-Generic)
If, however, you need to use some functionality which is specific to a BookPageViewController then it depends what it is you want to do. If there is a method on BookPageViewController like this:
func doSomething (input: Int) -> String
which doesn't make use of the generic parameter DataSource then probably you'll want to separate out that function into its own protocol/superclass which isn't generic. For example:
protocol DoesSomething {
func doSomething (input: Int) -> String
}
and then have BookPageViewController conform to it:
extension BookPageViewController: DoesSomething {
func doSomething (input: Int) -> String {
return "put your implementation here"
}
}
Now the return type of your function can be this non-generic protocol:
func currentPageController (at index: Int) -> DoesSomething {
if index == 0 {
return readingPageController()
}
return starsPageController()
}
and you can use it like this:
let pager = Pager()
let controller = pager.currentPageController(at: 0)
let retrievedValue = controller.doSomething(input: 7)
Of course, if the return type is no longer a UIViewController of any sort then you probably want to consider renaming the function and the related variables.
Custom Functionality (Generic)
The other option is that you can't separate out the functionality you need into a non-generic protocol/superclass because this functionality makes use of the generic parameter DataSource. A basic example is:
extension BookPageViewController {
func setDataSource (_ newValue: DataSource) {
self.dataSource = newValue
}
}
So in this case you really do need the return type of your function to be BookPageViewController<DataSource>. What do you do? Well, if what you really want is to use the setDataSource(_:) method defined above then you must have a DataSource object that you plan to pass in as an argument, right? If this is the case then we're making progress. Previously, you only had some Int value which you were passing into your function and the problem was that you couldn't specify your generic return type with that. But if you already have a BookPageDataSource value then it is at least logically possible for you to use this to specialize your
function.
What you say you want, however, is to just use an Int to get the controller at that index, regardless of what the DataSource type is. But if you don't care what the DataSource is of the returned BookPageViewController then how can you expect to set its DataSource to something else using the setDataSource(_:) method?
You see, the problem solves itself. The only reason you would need the return type of your function to be generic is if the subsequent functionality you need to make use of uses that generic type, but if this is the case then the controller you get back can't have just any old DataSource (you just wanted whichever one corresponds to the index you provide) - you need it to have exactly the type of DataSource which you plan to pass in when you use it, otherwise you're giving it the wrong type.
So the ultimate answer to your question is that, in the way that you were conceiving of it, there is no possible use for the function you were trying to construct. What's very cool about the way Swift is architected is that the compiler is actually able to figure out that logical flaw and prevent you from building your code until you've re-conceptualized it.
Footnote:
* It is possible to have a generic function which only uses the generic parameter in the return type and not in the input, but this won't help you here.

How to organize swift source code in pattern?

I have some codes in java which organized well, so it helps me manage source code as well as extend in future easily. These codes as follow
public interface IDataModel<T extends IDataModel> {
void copyData(T data);
long getUpdatedTime();
}
public abstract class AbstractDataModel<T extends IDataModel> implements IDataModel<T>{
protected long updatedTime;
public long getUpdatedTime(){
return updatedTime;
}
}
public class concreteDataA extends AbstractDataModel<concreteDataA>{
String property1;
public String getProperty1(){
return property1;
}
#override
public void copyData(concreteDataA data){
property1 = data.getProperty1();
updatedTime = data.getUpdatedTime();
}
}
Now i want to port into iOS swift 3.0. Is it possible to organize code in swift 3.0 as above? Or is there any equivalent way in swift to organize code as above? I'm quite new to swift iOS, so it makes me hard to organize source code in pattern. Thanks you.
You haven't provided much in the way of context, but it seems like you're struggling developing a "protocol-oriented" solution, as Swift folks like to call the pattern. Here are a couple of options that might solve your problem (spoiler – I think the problem is in your design):
Interface: Protocol, Abstract Class: Protocol Extension
Like #sulthan mentioned, you can certainly get to a similar place using protocols with default implementations, like so:
protocol DataModel {
mutating func copy(data: Self)
var updatedTime : Float { get }
}
extension DataModel {
var updatedTime : Float { return 0 }
}
However, you'll run into a problem when you try to implement the ConcreteDataModel since you want to specialize it to account for the property1 value that isn't mentioned in the protocol. Your options are to relax that requirement in ConcreteDataModel (aka don't do that) or use typecasting. Please note, fighting the typing system in Swift is a sure sign that your code is not idiomatic! You should see this difficulty as the language nudging you to reconsider your approach.
Use immutable data types
This is the most straight-forward answer. If what you've described above is actually a concrete example from your app, then you don't really need protocols at all. (In fact, your Java implementation is certainly over-abstracting.) Swift structs are immutable, which means that whenever you change them, you are actually changing a copy.
struct DataModel {
let updatedTime: Float
mutating func update(time: Float) {
self = DataModel(updatedTime: time)
}
}
var data1 = DataModel(updatedTime: 3)
var data2 = data1
data2.update(time: 17)
print(data1.updatedTime) // 3.0
print(data2.updatedTime) // 17.0
Model your behavior apart from your data
This is the generalized solution. From a design perspective, it's clear that you have two distinct concerns. You want something copyable, and you want something that tracks "time." Why not just let your code reflect that?
protocol Copier {
associatedtype Data
func copy(from: Data) -> Data
}
protocol Clock {
var time: Float { get }
}
class AlarmClock: Clock, Copier {
let time: Float
let alarm: Float
init(time: Float, alarm: Float) {
self.time = time
self.alarm = alarm
}
func copy(from: AlarmClock) -> AlarmClock {
return AlarmClock(time: from.time, alarm: from.alarm)
}
}
Of course, you could even go the last step and provide the default implementation for Clock.time if you really needed it.

Swift iOS take in a input and use it for function name

func callFunctionName(parameters: String) -> returnType
{
var somevalue = parameters
var returnValue = somevalue()
return returnValue
}
Is there a way to take in a input and use it as a function name?
example: let say input is green, I want to call function green. if input is red call function red etc...
Or to have a huge if statement to check each input to call different functions
This is not possible in Swift. You will have to store any functions you want to call in your own dictionary, and then use that to look up functions by name.
A "huge statement" might be feasible for a small number of functions, and it would certainly perform faster, but the ideal approach would be to store them in a dictionary.
However, if you are dealing with objects:
if exampleObject.respondsToSelector("exampleFunction")
{
exampleObject.performSelector("exampleFunction")
}
This approach currently works with all classes, be it Objective-C or Swift.
This is easily possible in Objective-C by using:
[self performSelector:NSSelectorFromString(#"green")];
But Swift is less dynamically typed than Objective-C and has less support for reflection. The Objective-C way I described above is very prone to crashes at runtime if the input (e.g. "purple" if you didn't have a function for purple) doesn't match a function that exists.
Using a big if statement is not an unreasonable way to approach it.
As the other answers said, an if statement is probably the best way to go about this.
override func viewDidLoad() {
if someValue = green {
green() //This will run whatever you have in the green() function below
}
}
func green() {
//put code for output of green here
}
Then all you have to do is make separate functions for all your outputs such as the green() func
This is the closest I could get. (And it's partially based on the answer of Vatsal Manot)
The idea is to use closures.
First of all we define the return type of the closure: let's use Int (of course you can change this later).
typealias colorClosureReturnType = Int
Now lets define the type of a closure that receives no parameters (you can change this too) and returns colorClosureReturnType
typealias colorClosureType = () -> (colorClosureReturnType)
Fine, now lets create a dictionary where the key is a String and the value is a closure of type colorClosureType:
let dict : [String: colorClosureType] = [
"red": { return 0 /* you can write here all the logic you need */ },
"green": { return 1 /* also here */},
"blue": { return 2 /* and here */}
]
Usually I let Swift Type Inference to infer the type of the variable/constant. But this time for sake of clarity I explicitly declared the type of the dictionary.
Now we can build a simple function that receives a String and return an optional colorClosureReturnType.
func callClosure(colorName: String) -> colorClosureReturnType? {
return dict[colorName]?()
}
As you can see the function look in the dictionary a closure associated to the key received as param. If it does found it then runs the closure and returns the results.
If the dictionary does not contain the requested key then the function returns nil. That's why the return type of this function is colorClosureReturnType? and not colorClosureReturnType.
Finally some tests:
callClosure("red") // 0
callClosure("green") // 1
callClosure("blue") // 2
func callFunctionName(parameters: String) -> ()
{
_ = NSTimer.scheduledTimerWithTimeInterval(0.1, target: self, selector: Selector(parameters), userInfo: nil, repeats: false)
}
func green() {
}

Extending Array to append SKTextures [duplicate]

This question already has answers here:
Is it possible to make an Array extension in Swift that is restricted to one class?
(4 answers)
Closed 7 years ago.
Being fairly new to Swift I decided I would look at extending Array (or more specifically [SKTexture] Arrays of SKTexture) with a function to add a specified number of frames from the application bundle.
// FRAMES
FuzzyRabbit_0001#2x.png
FuzzyRabbit_0002#2x.png
FuzzyRabbit_0003#2x.png
FuzzyRabbit_0004#2x.png
// CALL
var rabbitTextures = [SKTexture]()
self.rabbitTextures.textureFromFrames("FuzzyRabbit", count: 4)
My first attempt is listed below, I am getting the error Cannot invoke 'append' with an argument list of type '(SKTexture!)' which from looking at the function fuzzyPush is because I am trying to append an SKTexture rather than the generic T.
Is this possible, or am I limited by the fact that I don't want the function to be generic but rather specific to Arrays of SKTexture.
extension Array {
// ONLY SKTexture
mutating func textureFromFrames(imageName: String, count: Int) {
if !(self[0] is SKTexture) { return }
for index in 1...count {
let image = String(format: "\(imageName)_%04d", index)
let texture = SKTexture(imageNamed: image)
self.append(texture) // ERROR: Cannot invoke append with an argument list of type SKTexture!
}
}
// WORKS FINE
mutating func fuzzyPush(newItem: T) {
self.append(newItem)
}
}
I was just curious if this is something I could do with an extension, its not a problem as I have this as a function that takes 3 parameters (imageName, count, arrayToAppend) so I can quite easily use that.
This extension is not possible to write today. You cannot apply an extension method to only certain types of arrays.
There are two good solutions. You can use a HAS-A pattern by creating a struct (TextureList) that contains a [SKTexture], or you can use a function.
You can replace :
self.append(texture)
with
self.append(texture as T)
I checked this on an array of strings though and it worked.
About the first check add another check to see if the array is empty otherwise the self[0] is SKTexture will fail.
This is the code I tested on an online swift compiler (SKTexture was not available obviously) :
extension Array {
mutating func textureFromFrames(imageName: String, count: Int) {
for index in 1...count {
let image = String(format: "\(imageName)_%04d", index)
self.append(image as T)
}
}
}
var arr = Array<String>()
arr.textureFromFrames("testing", count:4)
for tmp in arr {
println("\(tmp)")
}

Filter array in a category/extension

For convenience, in a little experiment I am doing, I would like to extend Array to provide some app specific functionalities. This specific extension is not necessary best practice, but I am just curious about solving the Swift issues I am having.
Given a custom class Section, my extension (with partially extended closure) is:
extension Array {
func onlyFullSection() -> Array<Section> {
return self.filter {
(a:Section) -> Bool in
return a.isFullSection()
}
}
}
The error I get is: "T" is not a subtype of "Section".
I tried to fix it with all the sauces (changing types, casting, etc...) but still get similar errors.
This other variant:
extension Array {
func onlyFullSection() -> Array<Section> {
return (self as Array<Section>).filter {
(a:Section) -> Bool in
return a.isFullSection()
} as Array<Section>
}
throws: Cannot convert the expression's type 'Array<Section>' to type 'Array<Section>'
Any clue on what I am doing wrong? Thanks!
It is because you are extending T[] and not Section[]. That means that Int[] will also have your additional method. That might not be the best idea (since it will crash badly).
Swift currently does not allow you to extend a specialised generic type like Section[].
But if you really, really want to do it, here is one way to force a cast, use reinterpretCast, which Apple describes as follows
/// A brutal bit-cast of something to anything of the same size
func reinterpretCast<T, U>(x: T) -> U
You can use it like this:
extension Array {
func onlyFullSection() -> Section[] {
let sections : Section[] = reinterpretCast(self)
return sections.filter{ $0.isFullSection() }
}
}
But please don't.
The problem is that since the Array class is actually a generic Array<T>, you are extending Array<T>. And apparently you can't cast between generic types (i.e. <T> to <Section>), so I believe you'll have to make a new array and just push the appropriate objects into it.
17> extension Array {
18. func onlyFullSection() -> Array<Section> {
19. var ary = Array<Section>()
20. for s in self {
21. if (s as Section).isFullSection() {
22. ary.append(s as Section)
23. }
24. }
25. return ary
26. }
27. }
You could also create a helper method to convert between generic types for you, but in this instance that would just create an unnecessary temporary object.
Remember that the language is still heavily in flux so it's possible this will change. I think it's unlikely that we'll get the ability to cast between generic types, but I hope we'll at least be able to extend particular generics.

Resources