ARC of Swift protocol objects - memory-management

ARC is deinitializing my protocol objects that still have active references, is this a bug or is it expected behavior, and what is the workaround?
protocol SomeProtocol: class {
...
}
class SomeClass: SomeProtocol {
...
}
class ClassA {
var protocolObject: SomeProtocol!
...
}
class ClassB {
var x: SomeClass!
func f() {
self.x = SomeClass()
var objA = ClassA()
objA.protocolObject = self.x
}
}
In this example, when objA is deinitialized, it attempts to deinitialize objA.protocolObject, even though there is still a reference active as objB.x. This causes a runtime error EXC_BAD_ACCESS. However, if ClassA is defined as follows:
class ClassA {
var protocolObject: SomeClass
}
The code runs without error and protocolObject is not deinitialized. Any thoughts?

Update
This bug seems to be resolved as of iOS8.0.
I'm experiencing the same problem, and have narrowed down to the issue to the protocol being defined as a Class-Only Protocol (i.e. protocol XXX: class).
protocol FooProtocol {
var name: String { get }
}
// Note: Class-Only protocol
protocol BarProtocol: class {
var name: String { get }
}
class Foo: FooProtocol {
let name: String = "Foo"
deinit {
println("\(name) deinit")
}
}
class Bar: BarProtocol {
let name: String = "Bar"
deinit {
println("\(name) deinit")
}
}
class Container {
let foo: FooProtocol = Foo()
let bar: BarProtocol = Bar()
}
class ViewController: UIViewController {
let container = Container()
override func viewDidLoad() {
super.viewDidLoad()
// Prints 'Test: Foo'
test(container.foo)
// Prints 'Test: Bar', followed by 'Bar deinit'
// subsequent access to the `bar` variable results in a crash
test(container.bar)
}
func test(bar: BarProtocol) {
println("Test: \(bar.name)")
}
func test(foo: FooProtocol) {
println("Test: \(foo.name)")
}
}
Current workaround is to either forgo using class-only protocol. I have filed a bug report to Apple, rdar://18287447.

Related

How to write getter and setter for HasDelegate protocol in RxSwift?

I am implementing HasDelegate protocol to the IWDeviceManager.
In all the posts which I have read, no one has wrote getter & setter for this public var delegate property.
The compiler is explicitly asking me to write getter & setter for public var delegate. Why it's required in my case?
I tried writing but my code crashes when I try to get or set the delegate.
How do I solve this issue?
I have shared the code below
extension IWDeviceManager: HasDelegate {
public typealias Delegate = IWDeviceManagerDelegate
// Compiler explicitly asks to write getter and setter for this.
public var delegate: IWDeviceManagerDelegate? {
get { // Crashes here
return IWDeviceManager.shared()?.delegate
}
set(newValue) { // crashes here
IWDeviceManager.shared()?.delegate = newValue
}
}
}
Below is interface for IWDeviceManager
open class IWDeviceManager : NSObject {
weak open var delegate: IWDeviceManagerDelegate!
open class func shared() -> Self!
open func initMgr()
open func initMgr(with config: IWDeviceManagerConfig!)
}
Instead of using HasDelegate try this:
class IWDeviceManagerDelegateProxy
: DelegateProxy<IWDeviceManager, IWDeviceManagerDelegate>
, DelegateProxyType
, IWDeviceManagerDelegate {
init(parentObject: IWDeviceManager) {
super.init(parentObject: parentObject, delegateProxy: IWDeviceManagerDelegateProxy.self)
}
static func currentDelegate(for object: IWDeviceManager) -> Delegate? {
return object.delegate
}
static func setCurrentDelegate(_ delegate: IWDeviceManagerDelegate?, to object: IWDeviceManager) {
object.delegate = delegate
}
static func registerKnownImplementations() {
self.register { IWDeviceManagerDelegateProxy(parentObject: $0) }
}
}

How to write a factory function in swift?

There are a number of other questions floating around with various complicated answers for this question, but as far as I can see, none of them answer the basic question being posed:
How do you write a factory function that takes a type and returns an instance when the return type is known?
That is:
func factory<T>(T) -> Fooish { ... }
// Usage:
class Something : Fooish { ... }
let x:Fooish = factory(Something)
For example, this code:
public class Fooish {
var x:String = ""
public func foo() -> String {
return x
}
}
public class FooA : Fooish {
public override init() {
super.init()
x = "Hello"
}
}
public class FooB : Fooish {
public override init() {
super.init()
x = "World"
}
}
// This works
print(FooA().foo())
print(FooB().foo())
// This does not work
func factory<U>(type:U) -> Fooish {
return U()
}
print(factory(FooA).foo())
print(factory(FooB).foo())
Results in this error:
Sources/main.swift:32:10: error: 'U' cannot be constructed because it has no accessible initializers
return U()
^
<unknown>:0: error: build had 1 command failures
So what is the bound to place on T, such that we can call T() and know that the returned instance is a some Fooish?
Some answers suggest using a protocol for it, such as:
protocol IsFoo {
init()
}
factory<T: IsFoo>(t:T) -> Fooish { .. }
However, this doesn't seem to work:
error: cannot invoke 'factory' with an argument list of type '((FooA).Type)'
expected an argument list of type '(U)'
Every answer to this question seems to have multiple conflicting and updated answers; please, just simply post the snippet above, with a working implementation of the function factory, for swift 2.2.
Make a protocol which defines a common initializer to be called by the factory method:
protocol FactoryInitializable {
init ()
}
func factory<T: FactoryInitializable>(type: T.Type) -> T {
return T()
}
public class Fooish {
var x = ""
public func foo() -> String {
return x
}
}
public class FooA : Fooish, FactoryInitializable {
required public override init() {
super.init()
x = "This is FooA"
}
}
public class FooB : Fooish, FactoryInitializable {
required public override init() {
super.init()
x = "This is FooB"
}
}
let a = factory(FooA)
let b = factory(FooB)
print(a.x) // print: This is FooA
print(b.x) // print: This is FooB

Type variable in protocol - Swift 2

So I have a protocol, and in it I want a variable that is a class type. That way I can init that class from the variable.
Keep in mind that there will be many different classes. I made a quick example.
I get the error "type 'CashRegister' does not conform to protocol 'RegisterProtocol'"
This example isn't exactly what I'm doing, but it gets the point across. Thanks for the help.
protocol RegisterProtocol {
var currentBill: DollarBillProtocol {get set}
func makeNewBill()->DollarBillProtocol
}
extension RegisterProtocol {
func printCurrentBill() {
Swift.print(currentBill)
}
}
class CashRegister: RegisterProtocol {
var currentBill = OneDollarBill.self
func makeNewBill() -> DollarBillProtocol {
return currentBill.init()
}
}
protocol DollarBillProtocol {
// protocol that all bills have in common
}
class OneDollarBill: DollarBillProtocol {
required init(){
}
}
class FiveDollarBill: DollarBillProtocol {
required init(){
}
}
The way you declare currentBill in CashRegister makes it a var of type class. But the protocol RegisterProtocol requires this variable to be of type DollarBillProtocol in any class that implements the protocol. The compile error is because of this mismatch.
To make this more clear, you could declare the var with the explicit type, as follows:
class CashRegister: RegisterProtocol {
var currentBill: DollarBillProtocol = OneDollarBill() // or other initial value
}

Making a Swift class conform to a protocol that requires an init

I have the following protocol in Swift:
protocol FooConvertible{
typealias FooType
init(foo: FooType)
}
I can make Swift classes conform to it in the class definition:
class Bar: FooConvertible {
var baz: String = ""
required init(foo: String){
baz = foo
}
}
So far so good. However, the problem arises when I try to make a class conform to it in an extension (With Cocoa classes, it's my only option, as I don't have the source):
class Baz {
var baz = ""
}
extension Baz: FooConvertible{
required convenience init(foo: String) { // Insists that this should be in the class definition
baz = foo
}
}
extension NSURL: FooConvertible{
required convenience init(foo: String) { // this also fails for the same reason
}
}
This used to be possible, in previous versions of the language
What's the reason it was removed?
That would mean that all the XXXLiteralConvertible Protocols are banned from Cocoa classes!
Any chance you are trying to create something like this:
protocol FooConvertible : class {
typealias FooType
var baz : String { get set } // protocol extensions inits may need to know this
init(foo: FooType) // this is your designated initializer
}
extension FooConvertible {
// init(foo: String) {
// self.init(foo: foo)
// baz = foo
// }
// you can't do this because it could call it self recursively
init(num: Int) { // this init will call your designated init and can instantiate correctly
self.init(foo: "\(num)")
}
}
class Baz {
var baz = ""
}
class Bar: FooConvertible {
var baz: String = ""
required init(foo: String) { // designated initializer
baz = foo
}
}
Baz will now know about all inits of FooConvertible.
If so, I'm glad I could help. :)

Class variables not yet supported

I begin my project with a split view controller as initial view controller and start it automatically from storyboard.
Generally, an app with this UI have one and only one split view controller as root, so I create a static variable in the subclass and set it when initialisation was done.
So I want try this behaviour with swift.
I read the Swift programming language guide book on iBook about Type properties (with static and class keyword) and trying a piece of code to the job:
import UIKit
class SplitViewController: UISplitViewController {
class func sharedInstance() -> SplitViewController {
return SplitViewController.instance
}
class let instance: SplitViewController = nil
init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: NSBundle?) {
super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil)
self.initialization()
}
init(coder aDecoder: NSCoder!) {
super.init(coder: aDecoder);
self.initialization()
}
func initialization() {
SplitViewController.instance = self;
}
}
but I figured out when Xcode say the class keyword for type properties wasn't supported yet.
Did you have a solution to do this ?
Embedding a struct can work just fine as a workaround:
class SomeClass
{
// class var classVariable: Int = 0
// "Class variables not yet supported." Weird.
// Workaround:
private struct SubStruct { static var staticVariable: Int = 0 }
class var workaroundClassVariable: Int
{
get { return SubStruct.staticVariable }
set { SubStruct.staticVariable = newValue }
}
}
The SomeClass.workaroundClassVariable computed type property can then be used as if it were a stored type property.
Swift now has support for static variables in classes. This is not exactly the same as a class variable (because they aren't inherited by subclasses), but it gets you pretty close:
class X {
static let y: Int = 4
static var x: Int = 4
}
println(X.x)
println(X.y)
X.x = 5
println(X.x)
It seems to be possible to declare variables with static storage duration in file scope (as in C):
var sharedInstance: SplitViewController? = nil
class SplitViewController: UISplitViewController {
....
func initialization() {
sharedInstance = self
}
}
My preferred method is to just use a private file scope var outside of the class and then implement class/static getters and setters:
private var _classVar: Int = 0;
class SomeClass
{
public class var classVar: Int
{
get { return _classVar }
set { _classVar = newValue }
}
}
As of Swift 1.2 (available with Xcode 6.3b1 and onwards), static class properties and methods are supported.
class SomeClass
{
static var someVariable: Int = 0
}
Using a dispatch_once singleton model in Swift
Seems to be the best answer so far, avoiding the use of a global variable.
A solution enough similar than var in file scope but more customisable and near singleton is to use a struct which support static var as property of class
struct PersonSharedData {
static var backstore = ""
var data: String {
get { return PersonSharedData.backstore }
set { PersonSharedData.backstore = newValue }
}
}
class Person {
var shared=PersonSharedData() //<< pseudo class var
var family: String {
get { return shared.data }
set { shared.data=newValue }
}
var firstname = ""
var lastname = ""
var sexe: Sexe = .Unknown
}
Ok, with the solution of Nikolai that do the work. I post my changes in this thread for information
var instance: SplitViewController? = nil
class SplitViewController: UISplitViewController {
class func sharedInstance() -> SplitViewController? {
return instance;
}
init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: NSBundle?) {
super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil)
self.initialization()
}
init(coder aDecoder: NSCoder!) {
super.init(coder: aDecoder);
self.initialization()
}
func initialization() {
instance = self
}
}
and for example, in my appDelegate, I can access this static method like this
SplitViewController.sharedInstance()!.presentsWithGesture = false
The wording in the error heavily implies this will be a language feature in the future.
You may want to resort temporarily to declaring a property variable in the Application Delegate and retrieve it from there. Not ideal, definitely an anti-pattern, but would give you a central place to retrieve the UISplitViewController when needed.
You have to wrap the class variables inside an inner struct variable
class Store{
var name:String
var address:String
var lat:Int
var long:Int
init(name:String, address:String, lat:Int, long:Int){
self.name = name
self.address = address
self.lat = lat
self.long=long
}
private struct FACTORY_INITIALIZED_FLAG { static var initialized: Bool = false
static var myStoreList:[Store]?
static func getMyStoreList()->[Store]{
if !initialized{
println("INITIALIZING")
myStoreList = [
Store(name: "Walmart", address: "abcd", lat: 10, long: 20),
Store(name: "JCPenny", address: "kjfnv", lat: 23, long: 34)
]
initialized = true
}
return myStoreList!
}
}
}
var a = Store.FACTORY_INITIALIZED_FLAG.getMyStoreList()
var b = Store.FACTORY_INITIALIZED_FLAG.getMyStoreList()
// only prints INITIALIZING once
Try this:
class var instance: SplitViewController {
return nil
}
It is called Type Property in Swift.
You define type properties with the static keyword. For computed type properties for class types, you can use the class keyword instead to allow subclasses to override the superclass’s implementation. The example below shows the syntax for stored and computed type properties:
struct SomeStructure {
static var storedTypeProperty = "Some value."
static var computedTypeProperty: Int {
return 1
}
}
enum SomeEnumeration {
static var storedTypeProperty = "Some value."
static var computedTypeProperty: Int {
return 6
}
}
class SomeClass {
static var storedTypeProperty = "Some value."
static var computedTypeProperty: Int {
return 27
}
class var overrideableComputedTypeProperty: Int {
return 107
}
}
Read more at link below,
https://developer.apple.com/library/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Properties.html#//apple_ref/doc/uid/TP40014097-CH14-ID254

Resources