I need to subclass NSFileManager to add some need functions to it.
I created a subclass, added the functions and private variables, now I want to access the functions from another class like this. MyFileManager.defaultManager().awesomeFunction("Test")
Here is my code:
import UIKit
class AwesomeFileManager: NSFileManager {
private let awesomeLet = ["let1", "let2", "let3"]
func awesomeFunction(parameter: String) -> Bool! {
return true
}
}
Somehow I can not access the function from another class. What am I doing wrong?
I am using Swift 2.0
Override defaultManager and make sure it returns an instance of your class.
To avoid the subclassing of methods you need to access the new method, that task is better handled with an extension:
extension NSFileManager {
private struct AssociatedKey {
static var awesomeLet: [String]?
}
var awesomeLet: [String]? {
get {
return objc_getAssociatedObject(self, &AssociatedKey.awesomeLet) as? [String]
}
set {
if let value = newValue {
objc_setAssociatedObject(self, &AssociatedKey.awesomeLet, value, .OBJC_ASSOCIATION_COPY_NONATOMIC)
}
}
}
func awesomeFunction(parameter: String) -> Bool! {
return true
}
}
Because you can't add variables to an extensions, I gave you the code to add a associated key to store/retrieve any objects you want to add the extension.
Related
When developing UIKit apps it's quite easy to mock the UserDefaults by defining a protocol and injecting the needed implementation in the UIViewController.
protocol Defaults {
var numberOfHandsPlayed: Int { get set }
}
struct AppDefaults: Defaults {
static let shared = AppDefaults()
private let userDefaults = UserDefaults.standard
struct Keys {
private init() {}
static let numberOfHandsPlayed = "numberOfHandsPlayed"
}
var numberOfHandsPlayed: Int {
get {
userDefaults.integer(forKey: Keys.numberOfHandsPlayed)
}
set(numberOfHandsPlayed) {
userDefaults.setValue(numberOfHandsPlayed, forKey: Keys.numberOfHandsPlayed)
}
}
}
struct MockDefaults: Defaults {
var numberOfHandsPlayed: Int {
get {
// mocking behaviour
}
set(numberOfHandsPlayed) {
// mocking behaviour
}
}
class PracticeViewController: UIViewController {
private var defaults: Defaults?
// defaults can be set to MockDefaults or AppDefaults
}
But now with SwiftUI I can do the following using the #AppStorage property wrapper:
#AppStorage("numberOfHandsPlayed") var numberOfHandsPlayed: Int = 3
Is there a clean solution in SwiftUI to mock this property wrapper and have the same flexibility as in my UIKit example?
The AppStorage allows to specify storage to be used (by default standard UserDefaults), so this feature can be utilised for your purpose.
One of possible approaches is to subclass standard user defaults, and mock it later if/where needed.
class MyUserDefaults: UserDefaults {
// override/add anything needed here
}
struct DemoView: View {
#AppStorage("numberOfHandsPlayed", store: MyUserDefaults()) var numberOfHandsPlayed: Int = 3
// ... other code
I have already seen
Is it possible to allow didSet to be called during initialization in Swift?
for me it is not working..
I am working in project where I have created class below
protocol FileManagerHelper {
var fileName:String {get}
var fileCategory:FileCategory {get set}
var isFileExitsAtPath:Bool {get}
var filePath:String {get}
var fileType:FileTypes {get set}
}
class FileManager:FileManagerHelper {
// Other property
//STORED PROPERY INIT WHEN OBJECT WILL CREATED WITH FileCategory OBJECT
var fileCategory:FileCategory {
didSet {
switch fileCategory {
case .XYZ:
print("Test")
... other cases
}
}
required init(fileCategory:FileCategory,fileType:FileTypes = .Image) {
self.fileCategory = fileCategory
self.path = self.folderPath + self.fileName
}
}
did set method is not calling of fileCategory
NOTE: I don't want to give default value , I want to pass it runtime from init method
Tries
1) defer
use of self in method called $defer before all stored property are initialised
2) Create custom method that will assign that value and call it from init
private func setCategory(with category:FileCategory) {
self.fileCategory = category
}
Use of method call setCategory before stored property ...
I know that all stored property should be initialised before instance created. Till that instance will not been created so i won't call methods (using self) may be that why above solution not working
Please help me if any one have idea
For me, using the defer is better readable.
import Foundation
class A {
var b: String {
didSet {
print("didSet called with value: \(b)")
}
}
init(x: String) {
self.b = x
defer { self.b = x }
}
}
let a = A(x: "It's Working!") // didSet called with value: It's Working!
print(a.b) // It's Working
One way to solve this is to extract the didSet logic into a separate method and call this method from both didSet and init:
class FileManager: FileManagerHelper {
var fileCategory:FileCategory {
didSet {
didSetFileCategory()
}
}
required init(fileCategory:FileCategory,fileType:FileTypes = .Image) {
self.fileCategory = fileCategory
self.path = self.folderPath + self.fileName
didSetFileCategory()
}
private func didSetFileCategory() {
switch fileCategory {
case .XYZ:
print("Test")
//... other cases
}
}
}
I apologize beforehand if title is unclear, but I like to know how this is possible with some code snippets first:
ClassOne:
#objc protocol FetchProtocol
{
var someVar: Bool
{
get set
}
var someUIView: FetchProtocol
{
get set
}
func someFuncOne()
}
class ClassOne: UIViewController, FetchProtocol
{
...
#IBOutlet var someUIView: FetchProtocol!
....
}
ClassTwo:
#objc protocol FetchProtocol
{
var someVar: Bool
{
get set
}
var someTableView: FetchProtocol
{
get set
}
var someUIView: FetchProtocol
{
get set
}
func someFuncOne()
func someFuncTwo()
}
class ClassTwo: UIViewController, FetchProtocol
{
...
#IBOutlet var someTableView: FetchProtocol!
#IBOutlet var someUIView: FetchProtocol!
....
}
Both ClassOne and ClassTwo conform to the same FetchProtocol and both classes use the same someVar as well as someFuncOne, but ClassTwo also uses someTableView and someFuncTwo unique to only ClassTwo.
How can I use the same protocol between both classes, but the other class has "additional" different skeletal implementation?
For example, something like the following:
if let vc = currentVC as? FetchProtocol
{
if vc.someVar == true
{
// Check if vc is of class type ClassOne, call someFuncOne
// Otherwise if vc is of class type ClassTwo, call someFuncOne and someFuncTwo
}
}
Is something like the above possible using protocols and if so, how to properly implement it, or is there another alternative?
Your code doesn't compile and I think you're overcomplicating things and use protocols for the sake of using them.. There is no need to use any protocols at all if all you want to do is this:
if let vc = currentVC as? FetchProtocol
{
if vc.someVar == true
{
// Check if vc is of class type ClassOne, call someFuncOne
// Otherwise if vc is of class type ClassTwo, call someFuncOne and someFuncTwo
}
}
Why not delete all protocols and just do:
if currentVC.someVar {
if let class1 = currentVC as? ClassOne {
class1.someFuncOne()
} else if let class2 = currentVC as? ClassTwo {
class2.someFuncOne()
class2.someFuncTwo()
}
}
You don't really need protocols here because whether protocols exist or not, you still have to check whether currentVC is ClassOne or ClassTwo.
Protocols act like "black boxes". Consider this method:
func foo(fetchObj: FetchProtocol) {
fetchObj.someFuncOne()
}
foo doesn't care about what fetchObj really is. It just says "I don't care what you are, just do someFuncOne!"
What you're trying to do here is completely the opposite: "I do care what you are. If you're ClassOne, do this. If you're ClassTwo, do that."
Your problem is quite abstract, and pretty hard to follow, but this does what you're asking for. That being said, I suspect there's no need for you to be using protocols here at all.
protocol P1 {
var someVar1: String { get }
func func1();
}
protocol P2: P1 {
var someVar2: String { get }
func func2();
}
class C1: P1 {
var someVar1 = "String 1 in C1"
func func1() {
print(someVar1)
}
}
class C2: P2 {
var someVar1 = "String 1 in C2"
var someVar2 = "String 2 in C2"
func func1() {
print(someVar1)
}
func func2() {
print(someVar2)
}
}
func foo(with object: P1) {
object.func1()
if let object = object as? P2 {
object.func2()
}
}
print("Test case 1:")
foo(with: C1())
print("Test case 1:\n")
foo(with: C2())
I have a simple class:
class TableItem {
class func cellIden() -> String {
return "TableItem"
}
}
and a subclass of TableItem
class EditableItem {
override class func cellIden() -> String {
return "EditableItem"
}
}
Then, somewhere in my code, I have this:
var items: [TableItem] = [TableItem(), EditableItem()]
Now, what I want to do is, iterate through items and call each TableItem's static cellIden() function.
for i in items {
var iden = i.self.cellIden()
}
However, it tells me TableItem does not have a member called 'cellIden'
How can I call the static method of a class from its instance?
Note: I can't call TableItem.cellIden() because i can be a TableItem or an EditableItem
You need to get the runtime type of i. Every instance has a dynamicType property that returns its runtime (dynamic) type:
var iden = i.dynamicType.cellIden()
It's documented in The Swift Programming Language: “Dynamic Type Expression”.
Since you wish to interrogate an instance, rather than the class, you could provide an instance method (that would return the class's method). You need only do it in the base class, and this hides the implementation from the user ...
class TableItem {
class func cellIden() -> String {
return "TableItem"
}
func iCellIden() -> String {
return self.dynamicType.cellIden()
}
}
class EditableItem: TableItem {
override class func cellIden() -> String {
return "EditableItem"
}
}
var items: [TableItem] = [TableItem(), EditableItem()]
for i in items {
println("\(i.dynamicType.cellIden())") // Works, fine
println("\(i.iCellIden())") // Equivalent, but removes responsibility from calle
}
This is a relatively common design pattern:
https://stackoverflow.com/a/17015041/743957
It allows you to return a subclass from your init calls.
I'm trying to figure out the best method of achieving the same thing using Swift.
I do know that it is very likely that there is a better method of achieving the same thing with Swift. However, my class is going to be initialized by an existing Obj-C library which I don't have control over. So it does need to work this way and be callable from Obj-C.
Any pointers would be very much appreciated.
I don't believe that this pattern can be directly supported in Swift, because initialisers do not return a value as they do in Objective C - so you do not get an opportunity to return an alternate object instance.
You can use a type method as an object factory - a fairly contrived example is -
class Vehicle
{
var wheels: Int? {
get {
return nil
}
}
class func vehicleFactory(wheels:Int) -> Vehicle
{
var retVal:Vehicle
if (wheels == 4) {
retVal=Car()
}
else if (wheels == 18) {
retVal=Truck()
}
else {
retVal=Vehicle()
}
return retVal
}
}
class Car:Vehicle
{
override var wheels: Int {
get {
return 4
}
}
}
class Truck:Vehicle
{
override var wheels: Int {
get {
return 18
}
}
}
main.swift
let c=Vehicle.vehicleFactory(4) // c is a Car
println(c.wheels) // outputs 4
let t=Vehicle.vehicleFactory(18) // t is a truck
println(t.wheels) // outputs 18
The "swifty" way of creating class clusters would actually be to expose a protocol instead of a base class.
Apparently the compiler forbids static functions on protocols or protocol extensions.
Until e.g. https://github.com/apple/swift-evolution/pull/247 (factory initializers) is accepted and implemented, the only way I could find to do this is the following:
import Foundation
protocol Building {
func numberOfFloors() -> Int
}
func createBuilding(numberOfFloors numFloors: Int) -> Building? {
switch numFloors {
case 1...4:
return SmallBuilding(numberOfFloors: numFloors)
case 5...20:
return BigBuilding(numberOfFloors: numFloors)
case 21...200:
return SkyScraper(numberOfFloors: numFloors)
default:
return nil
}
}
private class BaseBuilding: Building {
let numFloors: Int
init(numberOfFloors:Int) {
self.numFloors = numberOfFloors
}
func numberOfFloors() -> Int {
return self.numFloors
}
}
private class SmallBuilding: BaseBuilding {
}
private class BigBuilding: BaseBuilding {
}
private class SkyScraper: BaseBuilding {
}
.
// this sadly does not work as static functions are not allowed on protocols.
//let skyscraper = Building.create(numberOfFloors: 200)
//let bigBuilding = Building.create(numberOfFloors: 15)
//let smallBuilding = Building.create(numberOfFloors: 2)
// Workaround:
let skyscraper = createBuilding(numberOfFloors: 200)
let bigBuilding = createBuilding(numberOfFloors: 15)
let smallBuilding = createBuilding(numberOfFloors: 2)
Since init() doesn't return values like -init does in Objective C, using a factory method seems like the easiest option.
One trick is to mark your initializers as private, like this:
class Person : CustomStringConvertible {
static func person(age: UInt) -> Person {
if age < 18 {
return ChildPerson(age)
}
else {
return AdultPerson(age)
}
}
let age: UInt
var description: String { return "" }
private init(_ age: UInt) {
self.age = age
}
}
extension Person {
class ChildPerson : Person {
let toyCount: UInt
private override init(_ age: UInt) {
self.toyCount = 5
super.init(age)
}
override var description: String {
return "\(self.dynamicType): I'm \(age). I have \(toyCount) toys!"
}
}
class AdultPerson : Person {
let beerCount: UInt
private override init(_ age: UInt) {
self.beerCount = 99
super.init(age)
}
override var description: String {
return "\(self.dynamicType): I'm \(age). I have \(beerCount) beers!"
}
}
}
This results in the following behavior:
Person.person(10) // "ChildPerson: I'm 10. I have 5 toys!"
Person.person(35) // "AdultPerson: I'm 35. I have 99 beers!"
Person(35) // 'Person' cannot be constructed because it has no accessible initializers
Person.ChildPerson(35) // 'Person.ChildPerson' cannot be constructed because it has no accessible initializers
It's not quite as nice as Objective C, since private means all the subclasses need to be implemented in the same source file, and there's that the minor syntax difference Person.person(x) (or Person.create(x) or whatever) instead of simply Person(x), but practically speaking, it works the same.
To be able to instantiate literally as Person(x), you could turn Person into a proxy class which contains a private instance of the actual base class and forwards everything to it. Without message forwarding, this works for simple interfaces with few properties/methods but it gets unwieldy for anything more complex :P
I think actually the Cluster pattern can be implemented in Swift using runtime functions. The main point is to replace the class of your new object with a subclass when initializing. The code below works fine though I think more attention should be paid to subclass' initialization.
class MyClass
{
var name: String?
convenience init(type: Int)
{
self.init()
var subclass: AnyClass?
if type == 1
{
subclass = MySubclass1.self
}
else if type == 2
{
subclass = MySubclass2.self
}
object_setClass(self, subclass)
self.customInit()
}
func customInit()
{
// to be overridden
}
}
class MySubclass1 : MyClass
{
override func customInit()
{
self.name = "instance of MySubclass1"
}
}
class MySubclass2 : MyClass
{
override func customInit()
{
self.name = "instance of MySubclass2"
}
}
let myObject1 = MyClass(type: 1)
let myObject2 = MyClass(type: 2)
println(myObject1.name)
println(myObject2.name)
protocol SomeProtocol {
init(someData: Int)
func doSomething()
}
class SomeClass: SomeProtocol {
var instance: SomeProtocol
init(someData: Int) {
if someData == 0 {
instance = SomeOtherClass()
} else {
instance = SomethingElseClass()
}
}
func doSomething() {
instance.doSomething()
}
}
class SomeOtherClass: SomeProtocol {
func doSomething() {
print("something")
}
}
class SomethingElseClass: SomeProtocol {
func doSomething() {
print("something else")
}
}
Basically you create a protocol that your class cluster inherits from. You then wrap around an instance variable of the same type and choose which implementation to use.
For example, if you were writing an array class that switched between a LinkedList or a raw array then SomeOtherClass and SomethingElseClass might be named LinkedListImplementation or PlainArrayImplementation and you could decide which one to instantiate or switch to based on whatever is more efficient.
There is a way to achieve this. Whether it is good or bad practice is for another discussion.
I have personally used it to allow for extension of a component in plugins without exposing the rest of the code to knowledge of the extensions. This follows the aims of the Factory and AbstractFactory patterns in decoupling code from the details of instantiation and concrete implementation classes.
In the example case the switching is done on a typed constant to which you would add in extensions. This kinda contradicts the above aims a little technically - although not in terms of foreknowledge. But in your case the switch might be anything - the number of wheels for example.
I don’t remember if this approach was available in 2014 - but it is now.
import Foundation
struct InterfaceType {
let impl: Interface.Type
}
class Interface {
let someAttribute: String
convenience init(_ attribute: String, type: InterfaceType = .concrete) {
self.init(impl: type.impl, attribute: attribute)
}
// need to disambiguate here so you aren't calling the above in a loop
init(attribute: String) {
someAttribute = attribute
}
func someMethod() {}
}
protocol _Factory {}
extension Interface: _Factory {}
fileprivate extension _Factory {
// Protocol extension initializer - has the ability to assign to self, unlike class initializers.
init(impl: Interface.Type, attribute: String) {
self = impl.init(attribute: attribute) as! Self;
}
}
Then in a concrete implementation file ...
import Foundation
class Concrete: Interface {
override func someMethod() {
// concrete version of some method
}
}
extension InterfaceType {
static let concrete = InterfaceType(impl: Concrete.self)
}
For this example Concrete is the "factory" supplied default implementation.
I have used this, for example, to abstract the details of how modal dialogs were presented in an app where initially UIAlertController was being used and migrated to a custom presentation. None of the call sites needed changing.
Here is a simplified version that does not determine the implementation class at runtime. You can paste the following into a Playground to verify its operation ...
import Foundation
class Interface {
required init() {}
convenience init(_ discriminator: Int) {
let impl: Interface.Type
switch discriminator {
case 3:
impl = Concrete3.self
case 2:
impl = Concrete2.self
default:
impl = Concrete1.self
}
self.init(impl: impl)
}
func someMethod() {
print(NSStringFromClass(Self.self))
}
}
protocol _Factory {}
extension Interface: _Factory {}
fileprivate extension _Factory {
// Protocol extension initializer - has the ability to assign to self, unlike class initializers.
init(impl: Interface.Type) {
self = impl.init() as! Self;
}
}
class Concrete1: Interface {}
class Concrete2: Interface {}
class Concrete3: Interface {
override func someMethod() {
print("I do what I want")
}
}
Interface(2).someMethod()
Interface(1).someMethod()
Interface(3).someMethod()
Interface(0).someMethod()
Note that Interface must actually be a class - you can't collapse this down to a protocol avoiding the abstract class even if it had no need for member storage. This is because you cant invoke init on a protocol metatype and static member functions cannot be invoked on protocol metatypes. This is too bad as that solution would look a lot cleaner.
We can take advantage of a compiler quirk - self is allowed to be assigned in protocol extensions - https://forums.swift.org/t/assigning-to-self-in-protocol-extensions/4942.
Thus, we can have in place something like this:
/// The sole purpose of this protocol is to allow reassigning `self`
fileprivate protocol ClusterClassProtocol { }
extension ClusterClassProtocol {
init(reassigningSelfTo other: Self) {
self = other
}
}
/// This is the base class, the one that gets circulated in the public space
class ClusterClass: ClusterClassProtocol {
convenience init(_ intVal: Int) {
self.init(reassigningSelfTo: IntChild(intVal))
}
convenience init(_ stringVal: String) {
self.init(reassigningSelfTo: StringChild(stringVal))
}
}
/// Some private subclass part of the same cluster
fileprivate class IntChild: ClusterClass {
init(_ intVal: Int) { }
}
/// Another private subclass, part of the same cluster
fileprivate class StringChild: ClusterClass {
init(_ stringVal: String) { }
}
Now, let's give this a try:
print(ClusterClass(10)) // IntChild
print(ClusterClass("abc")) // StringChild
This works the same as in Objective-C, where some classes (e.g. NSString, NSArray, NSDictionary) return different subclasses based on the values given at initialization time.