I have created a "lock" in Swift and an Atomic property wrapper that uses that lock, for my Swift classes as Swift lacks ObjC's atomic property attribute.
When I run my tests with thread sanitizer enabled, It always captures a data race on a property that uses my Atomic property wrapper.
The only thing that worked was changing the declaration of the property wrapper to be a class instead of a struct and the main question here is: why it works!
I have added prints at the property wrapper and lock inits to track the number of objects created, it was the same with struct/class, tried reproducing the issue in another project, didn't work too. But I will add the files the resembles the problem and let me know any guesses of why it works.
Lock
public class SwiftLock {
init() { }
public func sync<R>(execute: () throws -> R) rethrows -> R {
objc_sync_enter(self)
defer { objc_sync_exit(self) }
return try execute()
}
}
Atomic property wrapper
#propertyWrapper struct Atomic<Value> {
let lock: SwiftLock
var value: Value
init(wrappedValue: Value, lock: SwiftLock=SwiftLock()) {
self.value = wrappedValue
self.lock = lock
}
var wrappedValue: Value {
get {
lock.sync { value }
}
set {
lock.sync { value = newValue }
}
}
}
Model (the data race should happen on the publicVariable2 property here)
class Model {
#Atomic var publicVariable: TimeInterval = 0
#Atomic var publicVariable2: TimeInterval = 0
var sessionDuration: TimeInterval {
min(0, publicVariable - publicVariable2)
}
}
Update 1:
Full Xcode project: https://drive.google.com/file/d/1IfAsOdHKOqfuOp-pSlP75FLF32iVraru/view?usp=sharing
This is question is answered in this PR: https://github.com/apple/swift-evolution/pull/1387
I think this is those lines that really explains it 💡
In Swift's formal memory access model, methods on a value types are considered to access the entire value, and so calling the wrappedValue getter formally reads the entire stored wrapper, while calling the setter of wrappedValue formally modifies the entire stored wrapper.
The wrapper's value will be loaded before the call to
wrappedValue.getter and written back after the call to
wrappedValue.setter. Therefore, synchronization within the wrapper
cannot provide atomic access to its own value.
Related
I would like to create a property wrapper for CurrentValueSubject. I have done this like that:
#propertyWrapper
public class CurrentValue<Value> {
public var wrappedValue: Value {
get { projectedValue.value }
set { projectedValue.value = newValue }
}
public var projectedValue: CurrentValueSubject<Value, Never>
public init(wrappedValue: Value) {
self.projectedValue = CurrentValueSubject(wrappedValue)
}
}
This works but there is a little thing I would like to change with it - use struct instead of class. The problem with using struct for this is that sometimes I could get Simultaneous accesses error. And I know why, this happens when in sink from this publisher I would try to read the value from wrapped value. So for example with code like this:
#CurrentValue
let test = 1
$test.sink { _ in
print(self.test)
}
And I more or less know why - because when projectedValue executes its observation, wrapped value is still in process of setting its value. In class this is ok, because it would just change the value, but with struct it actually modifies the struct itself, so Im trying to write and read from it at the same time.
My question is - is there some clever way to overcome this, while still using struct? I don't want to dispatch async.
Also I know that #Projected works similarly to this propertyWrapper, but there is a big difference - Projected executes on willSet, while CurrentValueSubject on didSet. And Projected has the same issue anyway.
I know that I can read the value inside the closure, but sometimes Im using this with various function calls, that might eventually use self.test instead.
Try my implementation
#propertyWrapper
class PublishedSubject<T> {
var wrappedValue: T {
didSet {
subject.send(wrappedValue)
}
}
var projectedValue: some Publisher<T, Never> {
subject
}
private lazy var subject = CurrentValueSubject<T, Never>(wrappedValue)
init(wrappedValue: T) {
self.wrappedValue = wrappedValue
}
}
TL;DR
I have a class with no public initializers or instances that passes an instance of itself to a closure in another class. It does this through a mirror of the other class. When I go to access that instance from within the closure, I'm getting a EXC_BAD_ACCESS error, but other parameters passed to the closure are clearly accessible and do not result in a bad access error. I have no idea why. See code below for replication in a new project or a playground.
Detailed Explanation
I've been trying to figure out a way to implement class-specific access control, where multiple specific classes have sole access to another class containing variables and functions to be shared between them. All other classes would not have such access. Kind of like a static class, or a Singleton pattern, but with specific, class-named access control.
I thought I had something that would actually work in pure swift, (which is nice for me since I don't know Objective-C, and only started on swift about 16 months ago.) It's done in an almost anti-swift manner, so just bear with me - my goal is to start with something functional and move it towards elegance and beauty from there.
Even though I'm reasonably confident it should all work, I'm encountering a EXC_BAD_ACCESS error in a very unexpected place.
The "class-specific private" class that you are not allowed to access an instance of unless you are on its "okay" list, we can call the Restricted class.
The class(es) that is(are) allowed access to the Restricted class we can call the Accessor class(es).
The programmer must tell the Restricted class to call a function from the Accessor, and "drop in" an instance of the Restricted class by passing it as a parameter to that function. You do this by passing in the name of the function to be called, an instance of the Accessor class on which to call said function, and any parameters that the function would need in addition to the Restricted class instance.
I could make an enormous switch in the Restricted class, each case of which properly calls each function indicated on each of the Accessor classes...but to get around that excessive overhead/setup, I have the name of the function to be called on the Accessor classes passed in as a string, and accessed through a mirror. Since mirrors only reflect properties and not functions, the function must be a property with an assigned closure, instead of a traditional function.
We can call these closures DropClosures, since their purpose is to have the shared, Restricted class dropped into them. In fact we could call this whole pattern the "DropClosure Pattern". (Or maybe anti-pattern, I know it's kind of gruesome as-is.)
The properties of the "shared" instance of the Restricted class are stored internally as a private static dict (as json, basically). To generate an actual instance of itself, the Restricted class uses a private initializer that accepts that dict as a parameter. After a DropClosure runs with said initialized instance, the Restricted class uses a Mirror of that instance to store any changes back in the "shared" dict, and the instance will go out of scope unless a reference is made to it. So after each DropClosure completes its run, the instance passed to it is more or less useless as a representation of the "shared" aspect of the class, intentionally so.
I only do this because there is no way to require that all references to a certain weak reference also be weak. I don't want a class with access to the weak reference to assign a strong reference to the same instance and keep it in memory, that would defeat the access control goal by allowing the instance to be shared outside of its access scope. Since I can't force the instance to expire once the closure has completed, the next best thing is to remove the motivation for doing so by making the object no longer connected to the shared source after the closure completes.
This all theoretically works, and will compile, and will not throw any swift exceptions when run.
The Accessor (or any class that has an instance of an Accessor) calls RestrictedClass.run(), the run code validates the Accessor instance, finds the DropClosure in that instance, and passes in an instance of the Restricted class to that closure.
However, whenever I try to access that instance from within the DropClosure, it gives me the aforementioned bad access error, seemingly on a C or Objective-C level.
As far as I can tell, the instance should be accessible at this point, and none of the variables being used should be dropping out of scope yet.
At this point I'm totally spitballing - is it possible that there is something in the background that prevents a class with no public initializers from being passed through a mirror? Does it have to do with passing it into a closure called from that mirror? Is there some kind of hidden weak reference that's making the instance get ARC'd?
Please note that I've tried discarding the "weak" wrapper object and only passing in the Restricted instance to the closure, and I get the same bad access error. The error is independent of the instance being weakly referenced.
Code:
import Foundation
typealias DropClosureVoid<T: AnyObject & AccessRestricted> = (_ weaklyConnectedInterface: WeaklyConnectedInterface<T>, _ usingParameters: Any?)->Void
typealias DropClosureAny<T: AnyObject & AccessRestricted> = (_ weaklyConnectedInterface: WeaklyConnectedInterface<T>, _ usingParameters: Any?)->Any?
enum AccessError : Error {
case InvalidFunction
case InvalidAccessClass
}
protocol AccessRestricted {
static func run<T:AnyObject>(_ closureName:String, in classObject: T, with parameters:Any?) throws
static func runAndReturn<T:AnyObject>(_ closureName:String, in classObject: T, with parameters:Any?) throws -> Any?
}
///This class contains an instance that should be expected to only temporarily represent the original, even if a strong reference is made that keeps the value in scope.
class WeaklyConnectedInterface<T:AnyObject> {
weak var value:T?
init(_ value: T) {
self.value = value
}
}
class Accessor {
let restrictedClassPassable:DropClosureVoid<RestrictedAccessClass> = { weaklyConnectedInterface, parameters in
print(weaklyConnectedInterface) // **EXC_BAD_ACCESS error here**
//note that the error above happens even if I pass in the instance directly, without the WeaklyConnectedInterface wrapper.
//It's clearly an issue that occurs when trying to access the instance, whether the instance is wrapped in a the class that makes a weak reference to it or not, which means that it is inaccessible even when strongly referenced.
if let parameterDict = parameters as? [String:String] {
print(parameterDict["paramkey"] ?? "nil")
print(weaklyConnectedInterface)
weaklyConnectedInterface.value?.restrictedVariable = "I've changed the restricted variable"
}
}
let anotherRestrictedClassPassable:DropClosureAny<RestrictedAccessClass> = { weaklyConnectedInterface, parameters in
if let parameterDict = parameters as? [String:String] {
print(parameterDict["paramkey"] ?? "nil")
print(weaklyConnectedInterface.value?.restrictedVariable as Any)
return weaklyConnectedInterface.value?.restrictedVariable
}
return nil
}
func runRestrictedClassPassable() throws {
let functionName = "restrictedClassPassable"
print("trying validateClosureName(functionName)")
try validateClosureName(functionName)//this is in case you refactor/change the function name and the "constant" above is no longer valid
print("trying RestrictedAccessClass.run")
try RestrictedAccessClass.run(functionName, in: self, with: ["paramkey":"paramvalue"])
let returningFunctionName = "anotherRestrictedClassPassable"
print("trying validateClosureName(returningFunctionName)")
try validateClosureName(returningFunctionName)
print("trying RestrictedAccessClass.runAndReturn")
let result = (try RestrictedAccessClass.runAndReturn(returningFunctionName, in: self, with: ["paramkey":"ParamValueChanged"]) as! String?) ?? "NIL, something went wrong"
print("result is \(result)")
}
func validateClosureName(_ name:String) throws {
let mirror = Mirror(reflecting: self)
var functionNameIsPresent = false
for child in mirror.children {
if child.label != nil && child.label! == name {
functionNameIsPresent = true
break
}
}
guard functionNameIsPresent else {
print("invalid function")
throw AccessError.InvalidFunction
}
}
}
extension Mirror {
func getChildrenDict() -> [String:Any]
{
var dict = [String:Any]()
for child in children
{
if let name = child.label
{
dict[name] = child.value
}
}
return dict
}
}
class RestrictedAccessClass:AccessRestricted {
private static var shared:[String:Any] = [
"restrictedVariable" : "You can't access me!"
]
private static func validateType<T>(of classObject:T) throws {
switch classObject {
case is Accessor:
return
default:
print("Invalid access class")
throw AccessError.InvalidAccessClass
}
}
var restrictedVariable:String
private init() {
restrictedVariable = "You can't access me!"
}
private init(from json:[String:Any]) {
restrictedVariable = json["restrictedVariable"] as! String
}
static func run<T:AnyObject>(_ closureName:String, in classObject: T, with parameters:Any?) throws {
print("trying validateType(of: classObject) in run")
try validateType(of: classObject)
for child in Mirror(reflecting: classObject).children {
if let childName = child.label {
if childName == closureName {
let dropClosure = child.value as! DropClosureVoid<RestrictedAccessClass>
let selfInstance = RestrictedAccessClass(from:shared)
let interface = WeaklyConnectedInterface(selfInstance)
dropClosure(interface, parameters)
runCleanup(on: selfInstance)//parses any data changed by the end of the drop closure back into the dict for use in future instances. This means you mustn't try using the instance in an async closure. The correct way to do this would be to call run inside of an async closure, rather than putting an anync closure inside of the drop closure.
_ = interface.value
return
}
}
}
}
static func runAndReturn<T:AnyObject>(_ closureName:String, in classObject: T, with parameters:Any?) throws -> Any? {
print("trying validateType(of: classObject) in runAndReturn")
try validateType(of: classObject)
for child in Mirror(reflecting: classObject).children {
if let childName = child.label {
if childName == closureName {
let dropClosure = child.value as! DropClosureAny<RestrictedAccessClass>
let selfInstance = RestrictedAccessClass(from:shared)
let interface = WeaklyConnectedInterface(selfInstance)
let result = dropClosure(interface, parameters)
runCleanup(on: selfInstance)//parses any data changed by the end of the drop closure back into the dict for use in future instances. This means you mustn't try using the instance in an async closure. The correct way to do this would be to call run inside of an async closure, rather than putting an anync closure inside of the drop closure.
_ = interface.value
return result
}
}
}
return nil
}
private static func runCleanup(on instance:RestrictedAccessClass) {
shared = Mirror(reflecting:instance).getChildrenDict()
//once this function goes out of scope(or shortly thereafter), the instance passed will become useless as a shared resource
}
}
Code to encounter error:
I just put this in a new project's AppDelegate.application(didFinishLaunching). You can put all of the code above and below, in order, in a playground and it will break in the same spot, but not as clearly.
let accessor = Accessor()
do {
try accessor.runRestrictedClassPassable()
}
catch {
print(error.localizedDescription)
}
Updates
Whether zombie objects are turned on or off, I'm getting the same error message from Xcode: Thread 1: EXC_BAD_ACCESS (code=1, address=0x1a1ebac696e)
Running an analysis with Command+Shift+B reveals no warnings.
Running with all of the malloc options enabled reveals the following error:
Thread 1: signal SIGABRT, objc[somenumber]: Attempt to use unknown class 0xSomevalue
This just got weird...
Apparently, the "unknown class" is the project. I found this out by selecting the (i) bubble on the inline object inspector for the Restricted instance that was causing the crash. It gives me the following message:
Printing description of weaklyConnectedInterface:
expression produced error: error:
/var/folders/zq/_x931v493_vbyhrfc25z1yd80000gn/T/expr52-223aa0..swift:1:65:
error: use of undeclared type 'TestProject'
Swift._DebuggerSupport.stringForPrintObject(Swift.UnsafePointer<TestProject.RestrictedAccessClass>(bitPattern: 0x103450690)!.pointee)
^~~~~~~~~~~
I thought that maybe this would happen for other classes, so I tested, and it's able to access other project-level classes just fine. Only for this specific instance is the project "namespace" undefined.
Please find below required modifications (not many)... Tested with Xcode 11.2 / iOS 13.2.
1) made interface inout to pass it as-is original, otherwise it somehow copied loosing type information
typealias DropClosureVoid<T: AnyObject & AccessRestricted> =
(_ weaklyConnectedInterface: inout WeaklyConnectedInterface<T>, _ usingParameters: Any?)->Void
typealias DropClosureAny<T: AnyObject & AccessRestricted> =
(_ weaklyConnectedInterface: inout WeaklyConnectedInterface<T>, _ usingParameters: Any?)->Any?
2) fix places of usage (same in two places)
var interface = WeaklyConnectedInterface(selfInstance) // made var
dropClosure(&interface, parameters) // << copy closure args here was a reason of crash
3) ... and that's it - build & run & output
Note: I would recommend to avoid force unwrap and use the following
if let dropClosure = child.value as? DropClosureVoid<RestrictedAccessClass> {
dropClosure(&interface, parameters)
}
I think part of my problem is because Swift 4 has changed the way things like #objc work.
There are a lot of tutorials floating around, with a lot of different values, and I can't pick my way between what used to work in what version enough to figure out how to make it work in this version.
let delegate = UIApplication.shared.delegate as! AppDelegate
delegate.addObserver(self, forKeyPath: #keyPath(AppDelegate.session), options: [], context: nil)
// Warning: Argument of #keyPath refers to non-'#objc' property 'session'
Adding #objc to the var declaration just informs me that APISession can't be referenced in Objective-C. That seems to lead down the path towards requiring me to expose every class / variable I want to use this tool with to Obj-C, and that just seems backwards -- this is a newer feature, as I understand it, and it's just odd that Apple wouldn't make it work natively in Swift. Which, to me, suggests I'm misunderstanding or misapplying something, somewhere, somehow.
According to the docs:
In Objective-C, a key is a string that identifies a specific property of an object. A key path is a string of dot-separated keys that specifies a sequence of object properties to traverse.
Significantly, the discussion of #keyPath is found in a section titled "Interacting with Objective-C APIs". KVO and KVC are Objective-C features.
All the examples in the docs show Swift classes which inherit from NSObject.
Finally, when you type #keyPath in Xcode, the autocomplete tells you it is expecting an #objc property sequence.
Expressions entered using #keyPath will be checked by the compiler (good!), but this doesn't remove the dependency on Objective-C.
This is how I've applied #keyPath() in real project of mine. I used it to save & retrieve data to and from UserDefaults and I called that feature as AppSettings. Here's how things are going on...
1). I have a protocol called AppSettingsConfigurable It contains a couple of stuffs which are the setting features of my app...
//: AppSetting Protocol
#objc protocol AppSettingsConfigurable {
static var rememberMeEnabled : Bool { get set }
static var notificationEnabled : Bool { get set }
static var biometricEnabled : Bool { get set }
static var uiColor: UIColor? { get set }
}
2). I have class and I named it AppSettings. This is where saving and retrieving operation take place with UserDefaults
//: AppSettings
class AppSettings: NSObject {
fileprivate static func updateDefaults(for key: String, value: Any) {
// Save value into UserDefaults
UserDefaults.standard.set(value, forKey: key)
}
fileprivate static func value<T>(for key:String) -> T? {
// Get value from UserDefaults
return UserDefaults.standard.value(forKey: key) as? T
}
}
3). Here's where BIG things are happened. Conform AppSettings class to our protocol and lets implement the stuffs using #keyPath().
//: Conform to protocol
extension AppSettings:AppSettingsConfigurable{
/** get & return remember me state */
static var rememberMeEnabled: Bool {
get { return AppSettings.value(for: #keyPath(rememberMeEnabled)) ?? false }
set { AppSettings.updateDefaults(for: #keyPath(rememberMeEnabled), value: newValue) }
}
/** get & return notification state */
static var notificationEnabled: Bool {
get { return AppSettings.value(for: #keyPath(notificationEnabled)) ?? true }
set { AppSettings.updateDefaults(for: #keyPath(notificationEnabled), value: newValue) }
}
/** get & return biometric state */
static var biometricEnabled: Bool {
get { return AppSettings.value(for: #keyPath(biometricEnabled)) ?? false}
set { AppSettings.updateDefaults(for: #keyPath(biometricEnabled), value: newValue) }
}
/** get & return biometric state */
static var uiColor: UIColor? {
get { return AppSettings.value(for: #keyPath(uiColor)) }
set { AppSettings.updateDefaults(for: #keyPath(uiColor), value: newValue!) }
}
}
PS: Noticed something different with uiColor from the rest? Nothing wrong with it as it's optional and it's allowed to accept the nil
Usage:
//: Saving...
AppSettings.biometricEnabled = true
//: Retrieving...
let biometricState = AppSettings.biometricEnabled // true
Let's say I have a protocol :
public protocol Printable {
typealias T
func Print(val:T)
}
And here is the implementation
class Printer<T> : Printable {
func Print(val: T) {
println(val)
}
}
My expectation was that I must be able to use Printable variable to print values like this :
let p:Printable = Printer<Int>()
p.Print(67)
Compiler is complaining with this error :
"protocol 'Printable' can only be used as a generic constraint because
it has Self or associated type requirements"
Am I doing something wrong ? Anyway to fix this ?
**EDIT :** Adding similar code that works in C#
public interface IPrintable<T>
{
void Print(T val);
}
public class Printer<T> : IPrintable<T>
{
public void Print(T val)
{
Console.WriteLine(val);
}
}
//.... inside Main
.....
IPrintable<int> p = new Printer<int>();
p.Print(67)
EDIT 2: Real world example of what I want. Note that this will not compile, but presents what I want to achieve.
protocol Printable
{
func Print()
}
protocol CollectionType<T where T:Printable> : SequenceType
{
.....
/// here goes implementation
.....
}
public class Collection<T where T:Printable> : CollectionType<T>
{
......
}
let col:CollectionType<Int> = SomeFunctiionThatReturnsIntCollection()
for item in col {
item.Print()
}
As Thomas points out, you can declare your variable by not giving a type at all (or you could explicitly give it as type Printer<Int>. But here's an explanation of why you can't have a type of the Printable protocol.
You can't treat protocols with associated types like regular protocols and declare them as standalone variable types. To think about why, consider this scenario. Suppose you declared a protocol for storing some arbitrary type and then fetching it back:
// a general protocol that allows for storing and retrieving
// a specific type (as defined by a Stored typealias
protocol StoringType {
typealias Stored
init(_ value: Stored)
func getStored() -> Stored
}
// An implementation that stores Ints
struct IntStorer: StoringType {
typealias Stored = Int
private let _stored: Int
init(_ value: Int) { _stored = value }
func getStored() -> Int { return _stored }
}
// An implementation that stores Strings
struct StringStorer: StoringType {
typealias Stored = String
private let _stored: String
init(_ value: String) { _stored = value }
func getStored() -> String { return _stored }
}
let intStorer = IntStorer(5)
intStorer.getStored() // returns 5
let stringStorer = StringStorer("five")
stringStorer.getStored() // returns "five"
OK, so far so good.
Now, the main reason you would have a type of a variable be a protocol a type implements, rather than the actual type, is so that you can assign different kinds of object that all conform to that protocol to the same variable, and get polymorphic behavior at runtime depending on what the object actually is.
But you can't do this if the protocol has an associated type. How would the following code work in practice?
// as you've seen this won't compile because
// StoringType has an associated type.
// randomly assign either a string or int storer to someStorer:
var someStorer: StoringType =
arc4random()%2 == 0 ? intStorer : stringStorer
let x = someStorer.getStored()
In the above code, what would the type of x be? An Int? Or a String? In Swift, all types must be fixed at compile time. A function cannot dynamically shift from returning one type to another based on factors determined at runtime.
Instead, you can only use StoredType as a generic constraint. Suppose you wanted to print out any kind of stored type. You could write a function like this:
func printStoredValue<S: StoringType>(storer: S) {
let x = storer.getStored()
println(x)
}
printStoredValue(intStorer)
printStoredValue(stringStorer)
This is OK, because at compile time, it's as if the compiler writes out two versions of printStoredValue: one for Ints, and one for Strings. Within those two versions, x is known to be of a specific type.
There is one more solution that hasn't been mentioned on this question, which is using a technique called type erasure. To achieve an abstract interface for a generic protocol, create a class or struct that wraps an object or struct that conforms to the protocol. The wrapper class, usually named 'Any{protocol name}', itself conforms to the protocol and implements its functions by forwarding all calls to the internal object. Try the example below in a playground:
import Foundation
public protocol Printer {
typealias T
func print(val:T)
}
struct AnyPrinter<U>: Printer {
typealias T = U
private let _print: U -> ()
init<Base: Printer where Base.T == U>(base : Base) {
_print = base.print
}
func print(val: T) {
_print(val)
}
}
struct NSLogger<U>: Printer {
typealias T = U
func print(val: T) {
NSLog("\(val)")
}
}
let nsLogger = NSLogger<Int>()
let printer = AnyPrinter(base: nsLogger)
printer.print(5) // prints 5
The type of printer is known to be AnyPrinter<Int> and can be used to abstract any possible implementation of the Printer protocol. While AnyPrinter is not technically abstract, it's implementation is just a fall through to a real implementing type, and can be used to decouple implementing types from the types using them.
One thing to note is that AnyPrinter does not have to explicitly retain the base instance. In fact, we can't since we can't declare AnyPrinter to have a Printer<T> property. Instead, we get a function pointer _print to base's print function. Calling base.print without invoking it returns a function where base is curried as the self variable, and is thusly retained for future invocations.
Another thing to keep in mind is that this solution is essentially another layer of dynamic dispatch which means a slight hit on performance. Also, the type erasing instance requires extra memory on top of the underlying instance. For these reasons, type erasure is not a cost free abstraction.
Obviously there is some work to set up type erasure, but it can be very useful if generic protocol abstraction is needed. This pattern is found in the swift standard library with types like AnySequence. Further reading: http://robnapier.net/erasure
BONUS:
If you decide you want to inject the same implementation of Printer everywhere, you can provide a convenience initializer for AnyPrinter which injects that type.
extension AnyPrinter {
convenience init() {
let nsLogger = NSLogger<T>()
self.init(base: nsLogger)
}
}
let printer = AnyPrinter<Int>()
printer.print(10) //prints 10 with NSLog
This can be an easy and DRY way to express dependency injections for protocols that you use across your app.
Addressing your updated use case:
(btw Printable is already a standard Swift protocol so you’d probably want to pick a different name to avoid confusion)
To enforce specific restrictions on protocol implementors, you can constrain the protocol's typealias. So to create your protocol collection that requires the elements to be printable:
// because of how how collections are structured in the Swift std lib,
// you’d first need to create a PrintableGeneratorType, which would be
// a constrained version of GeneratorType
protocol PrintableGeneratorType: GeneratorType {
// require elements to be printable:
typealias Element: Printable
}
// then have the collection require a printable generator
protocol PrintableCollectionType: CollectionType {
typealias Generator: PrintableGenerator
}
Now if you wanted to implement a collection that could only contain printable elements:
struct MyPrintableCollection<T: Printable>: PrintableCollectionType {
typealias Generator = IndexingGenerator<T>
// etc...
}
However, this is probably of little actual utility, since you can’t constrain existing Swift collection structs like that, only ones you implement.
Instead, you should create generic functions that constrain their input to collections containing printable elements.
func printCollection
<C: CollectionType where C.Generator.Element: Printable>
(source: C) {
for x in source {
x.print()
}
}
I want to lazy/inline implement a protocol in Swift.
So in the point of the implementation I will have access to variables outside the protocol scope ,
Same as implementing a interface in Java without declaring a class:
class MyClass:UIView {
var someComponent:SomeInnerComponent = SomeInnerComponent();
var count:Int = 0;
var a = :SomeProtocol { //<----- IS THIS POSSIBLE, IF YES HOW ?
func a0() {MyClass.count--}
func a1() {MyClass.count++}
}
someComponenet.delegate = a;
}
protocol SomeProtocol {
func a0()
func a1()
}
editing----
thanks i look at this solution, and i didn't see how to access a variable of the parent class.
all the examples show an Anonymous class but no one of the examples is accessing the parent variables .
What you're looking for is an inner class (not necessarily an anonymous one), declared in a scope that lets it access the count variable of a MyClass instance, and that adopts a protocol defined at a different scope. Right now Swift has a few of those pieces, but it doesn't look like you can put them all together in any way that's as concise as what you might be looking for.
You might think about declaring an inner class:
class MyView: UIView {
let someComponent = SomeInnerComponent() // type SomeInnerComponent is inferred
var count = 0 // type Int is inferred
class Helper: SomeProtocol {
func a0() { count-- } // ERROR
// ...
}
init() {
someComponent.delegate = Helper()
}
}
But that won't work, because count is implicitly self.count, where self is a Helper instance, not the MyView instance that "owns" the Helper instance. And there isn't a way to reference that MyView instance (or its properties) from within a Helper's methods, because you could just as well construct a MyView.Helper() without having an existing MyView instance. Inner classes (or nested types in general) in Swift nest only in lexical scope, not in existential ownership. (Or to put it another way, since you referenced Java: all inner classes in Swift are like static inner classes in Java. There's no non-static inner class.) If that's a feature you'd like, though, it's probably worth telling Apple you want it.
You could also try declaring Helper inside MyView.init() -- in Swift you can nest type definitions anywhere, including inside functions or methods of other types. Defined there, it can refer to MyView's properties. However, now the type information for Helper is only visible inside of MyView.init(), so when you assign it to someComponent.delegate (whose type is just SomeProtocol), you can't make use of it... this crashes the compiler, even. (That's another bug to report, but it's hard to say whether the bug is really "compiler crashes on valid usage" or "code is bad, but compiler crashes instead of producing error".)
The closest solution I can come up with looks something like this:
class SomeInnerComponent {
var delegate: SomeProtocol?
}
protocol SomeProtocol {
func a0()
func a1()
}
class MyClass {
var someComponent = SomeInnerComponent()
var count = 0
struct Helper: SomeProtocol {
var dec: () -> ()
var inc: () -> ()
func a0() { dec() }
func a1() { inc() }
}
init() {
someComponent.delegate = Helper(
dec: { self.count -= 1 }, // see note below
inc: { self.count += 1 }
)
}
}
How it works:
Helper is an inner struct (could be a class, but a struct is simpler)
It implements the a0 and a1 methods, satisfying the requirements of SomeProtocol
The implementations of a0 and a1 call through to the closures dec and inc, which are stored properties (aka instance variables) of the Helper struct
You write (or otherwise specify) these closures when you construct a Helper instance (using the default member-wise initializer, Helper(dec: (Void -> Void), inc: (Void -> Void)))
Because you can write the closures when initializing a Helper, those closures can capture variables where you're calling the initializer, including the implicit self that refers to the MyClass instance creating the Helper.
You need both a0/a1 and dec/inc because you need closures (the latter), not methods, for capturing the enclosing state. And even though closures and funcs/methods are in many ways interchangeable, you can't create a method/func implementation by assigning a closure to a method/func name. (It'd be a different story if SomeProtocol required closure properties instead of methods, but I'm assuming SomeProtocol isn't something under your control.)
Anyway, this is kind of a lot of boilerplate and a layer of abstraction that you might not really need, so it's probably worth looking into other ways to architect your code.
Note: my example uses the closure { self.count -= 1 } where you might expect { self.count-- }. The latter doesn't work because that's an expression with a value, so Swift will interpret it as shorthand for the closure's return value. Then it'll complain that you assigned a () -> Int closure to a property that expects a () -> () (aka Void -> Void) closure. Using -= 1 instead works around this issue.
I would go for a different approach, I know this a pretty old topic but just in case someone else struggles with this issue:
class MyClass:UIView {
var someComponent:SomeInnerComponent = SomeInnerComponent();
var count:Int = 0;
init(){
// Assign the delegate or do it somewhere else to your preference:
someComponenet.delegate = ProtocolImplementation(myClass: self);
}
private class ProtocolImplementation: SomeProtocol {
let selfReference: MyClass
init(myClass: MyClass){
selfReference = myClass
}
public func a0(){
selfReference.count--
}
public func a1(){
selfReference.count++
}
}
}
protocol SomeProtocol {
func a0()
func a1()
}
By following this approach it's also possible to include the same protocol multiple times, lets say your Protocol supports a generic and you want to implement it twice. SomeProtocol< SomeObject > and SomeProtocol< OtherObject > could be both used this way if needed.
Kind regards