Init an empty NSZone struct with Swift 3 - ios

In Swift 2, I was able to initialize an empty NSZone struct like so:
let z = NSZone() // ObjectiveC.NSZone
I used this to stub test calls that required NSZone. With Swift 3, the interface was changed so that the initializer is no longer available:
Swift 2.3:
public struct NSZone : NilLiteralConvertible {
public init()
/// Create an instance initialized with `nil`.
public init(nilLiteral: ())
}
Swift 3:
public struct NSZone {
}
Is Apple pushing to use an optional NSZone instead of the old NSZone() initializer which initialized NSZone with a nil value?
Try to extend NSZone to add an initializer results in an error:
extension NSZone {
init() { } // Return from initializer without initializing all stored properties
}

Per the Swift open source project's design doc for importing ObjC API into Swift 3:
Nullable NSZone parameters are given a default value of nil. Zones are essentially unused in Swift and should always be nil.
If you're testing any calls that require a zone, you should be passing nil anyway.

Related

Why Swift protocol conforming values are treated as Value types by default?

I have a protocol, which only describes an interface.
protocol SampleProtocol {
var message: String? { get set }}
Why does the compiler treat the conforming value/object always as a Value type?
Sample Example,
// Protocol value usage
import Foundation
protocol SampleProtocol {
var message: String? { get set }
}
final class SampleObject: SampleProtocol {
var message: String?
}
final class Controller {
var sampleValue: SampleProtocol! {
didSet {
print("New value has been set")
}
}
}
let controller = Controller()
controller.sampleValue = AlphaObject() // Correctly prints "New value has been set"
controller.sampleValue.message = "New message" // Prints again "New value has been set", like for value types
Your protocol SampleProtocol could be adopted by a class or a struct. Swift is using the behavior of the value type which is the more restrictive type until you tell it that the protocol will only be used by a class reference type.
Add conformance to AnyObject to your protocol to get reference type behavior:
protocol SampleProtocol: AnyObject {
var message: String? { get set }
}
See The Swift 5.1 Programming Guide - Class-Only Protocols for more details.
The guide notes:
Use a class-only protocol when the behavior defined by that protocol’s
requirements assumes or requires that a conforming type has reference
semantics rather than value semantics.
Historical note: Using class keyword:
Prior to Swift 4.0, this was written using the class keyword:
protocol SampleProtocol: class {
var message: String? { get set }
}
This still works for the time being, but it is currently just a type alias for AnyObject and will likely be removed in a later version of Swift.
It doesn’t create a copy of the object. It is the same object in both calls – if you put print(Unmanaged.passUnretained(sampleValue as AnyObject).toOpaque()) in didSet you will see that the address is the same. Compiler doesn’t know it’s dealing with a value type or a reference type. If you put a class keyword in protocol declaration like so:
protocol SampleProtocol: class { ... }
the didSet will be called once, because compiler knows it's a reference type and will not reassign reference.
I guess different setters generated depends on type of property

Can I initialize a Codable Model from a different model in a Swift extension?

I have a codable model
public final class MyCodableModel: Codable {
public let id: Int
}
I also have another model that happens to have the same variables inside it.
public final class MyOtherModel {
public let id: Int
}
Now, I want to instantiate MyCodableModel using MyOtherModel in an extension. I don't want to modify MyCodableModel directly because of dependency issues.
I first tried to use a normal initializer in my extension, but it said I needed to use a convenience initializer, so then I ended up with this:
extension MyCodableModel {
convenience init?(myOtherModel: MyOtherModel) {
id = myOtherModel.id
}
}
But the error says 'let' property 'id' may not be initialized directly; use "self.init(...)" or "self = ..." instead. I assume this is because I'm not using the designated initializer of init(from: Decoder).
Is there another way to do this? Or will I not be able to convert MyOtherModel to a MyCodableModel?

iOS - Not able to access Static method of swift class

I want to access Swift code in Objective-c.
I have written one class in swift which contains static method. I want to access that Static Method in objective C Class.
Here is Class declaration:
#objc class LocalizedResource: NSObject {
/*!
* #discussion This function will get localize string for key
* #param key Localize key
* #return String for locaized key
* #code LocalizedResource.getStringForKey(key);
*/
static func getStringForKey(key:String) -> String {
let frameworkBundle = NSBundle.mainBundle()
let value = frameworkBundle.localizedStringForKey(key, value: nil, table: nil)
return value;
}
}
I have made following settings for it:
Product Module Name : MyProject
Defines Module : YES
Embedded Content Contains Swift : YES
Install Objective-C Compatibility Header : YES
Objective-C Bridging Header : $(SRCROOT)/MySources/SwiftBridgingHeader.h
Also I have added #Obj before my class declaration in Swift class.
I have import MyProject-Swift.h in the .m file where I want to access that method.
But when I am trying to access it, it is not allowing me to access that static method.
Is any one having solution for it? Is there something missing?
Thnaks.
Note in Swift 4 and the build setting swift 3 #objc inference is default, we must explicitly mark function as #objc, or it will not generate class function in Swift bridge header.
From your comment:
I am calling this method as follows:
errorMessage.text = LocalizedResource.getStringForKey(#"TIMED_OUT_ERROR");
In Objective-C, the "dot syntax" is used for properties,
not for methods. The correct call should be
errorMessage.text = [LocalizedResource getStringForKey:#"TIMED_OUT_ERROR"];

Using Swift Shared Instance in Objective C

I have a shared instance of a class in Swift that I'm using in Objective-C. I'm unable to create the shared instance and use the instance function. Here's my Swift code.
class VideoPlayerSignaler: NSObject {
static let sharedInstance = VideoPlayerSignaler()
let playerAction = Signal<PlayerAction>()
private override init() {
}
func firePlayerAction(action: PlayerAction) {
playerAction.fire(action)
}
}
Here's my Objective-C code.
VideoPlayerSignaler *signaler = [VideoPlayerSignaler sharedInstance];
// This is the line that is producing the issue.
// It's as if the signaler variable is a Class Instance
[signaler firePlayerAction: PlayerAction.Stop];
The error I'm producing states that firePlayerAction does not exist. In essence, Objective C believes the signaler variable to be a class instance.
What am I doing wrong and how do I fix it so that signaler is a shared instance of VideoPlayerSignaler?
There's nothing wrong with your Swift, or with how you access the singleton instance from ObjC — the problem is the enum value you're passing to it.
Presumably your enum declaration looks something like this:
enum PlayerAction: Int {
case Stop, Collaborate, Listen // etc
}
To make your enum accessible to ObjC, you need to preface the declaration with #objc:
#objc enum PlayerAction: Int { /*...*/ }
This makes it appear as a Cocoa-style NS_ENUM declaration in ObjC, creating global symbols for case names by concatenating the Swift enum type's name with the case names:
typedef NS_ENUM(NSInteger, PlayerAction) {
PlayerActionStop = 1,
PlayerActionCollaborate,
PlayerActionListen, // etc
};
So those names are what you should be passing when you call a method taking an enum value from ObjC:
[signaler firePlayerAction: PlayerActionStop]; // NOT PlayerAction.Stop
(The only docs I can find to cite for this are buried in the Attributes chapter in The Swift Programming Language — scroll down the to objc attribute.)

How to use generic protocol as a variable type

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()
}
}

Resources