Swift. RawRepresentable init with optional RawValue - swift

I am trying to make a generic failable initializer with optional parameter for RawRepresentable, basically this https://www.natashatherobot.com/swift-failable-enums-with-optionals/
There were a couple of methods proposed one of which is this (EDIT: fixed let in the second clause):
extension RawRepresentable {
init?(rawValue optionalRawValue: RawValue?) {
guard let rawValue = optionalRawValue, let value = Self(rawValue: rawValue) else { return nil }
self = value
}
}
from here https://gist.github.com/okla/e5dd8fbb4e604dabcdc3
I have no idea if it was ever working on Swift 2 but I can't compile it on Swift 3. I get:
Command failed due to signal: Segmentation fault: 11
Is there a way to make it work?
P.S. I am aware of other approaches from the article and its comments.
EDIT: Fixed broken copy/pasted code.

I just copied and pasted your code in a Playground, and the only error I get is that it's missing a let before assigning value in the guard statement.
Are you sure the segmentation fault is because of this extension?
This is the code that works for me (Xcode 8.2.1, Swift 3.0.2):
extension RawRepresentable {
init?(rawValue optionalRawValue: RawValue?) {
guard let rawValue = optionalRawValue, let value = Self(rawValue: rawValue) else { return nil }
self = value
}
}
-- EDIT --
After defining an enum with raw values I do get an error.
Adding this makes the Playground to crash:
enum Counter: Int {
case one = 1, two, three, four, five
}
Fixed it by renaming the parameter in init? to be init?(optRawValue optionalRawValue: RawValue?). I guess the problem is that you are calling Self(rawValue: rawValue) inside init?, and the compiler does not know which one to use...

Regardless of the problems with compiling this code or making it work as you'd like it to, I'd argue that you're trying to solve the underlying problem in the wrong way.
Trying to design an initializer like this is an anti-pattern: the design for Optionals in Swift encourages handling and resolving nullability questions at the earliest opportunity, not cascading failures so far that it's hard to recover their origins. If you have a function/initializer that returns nil if and only if it's passed nil, it just shouldn't accept nil in the first place and never return nil.
In Swift 3, you can keep the default rawValue initializer for your enum and resolve the issues from that original NatashaTheRobot post in either of a couple of different ways.
Use a compound if (or guard) statement.
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
guard let string = segue.identifier,
let identifier = SegueIdentifier(rawValue: string)
else { return /* or fatalError or whatever for catching problems */ }
switch identifier {
// handle all the enum cases here
}
}
Do it functional style with flatMap (twice), which executes a closure iff its input is not nil:
segue.identifier.flatMap(SegueIdentifier.init).flatMap { identifier in
switch identifier {
// handle all cases
}
}
Either way, you're unwrapping both levels of optionality (whether the segue has an identifier, and whether that string is a valid raw value for your SegueIdentifier enum) before the switch, which means that the switch must handle all valid SegueIdentifier cases. In turn, that means you catch yourself if you later add a new SegueIdentifier case and don't handle it. (As opposed to switching on something that might be a valid SegueIdentifier or might be nil, which means you need a default case, which means you'll silently fail if there are new SegueIdentifiers you ought to be handling.)

had to add public to init and it compiles and passes tests
Apple Swift version 4.1.2 (swiftlang-902.0.54 clang-902.0.39.2)
Target: x86_64-apple-darwin17.6.0
extension RawRepresentable {
public init?(rawValue optionalRawValue: RawValue?) {
guard let rawValue = optionalRawValue, let value = Self(rawValue: rawValue) else { return nil }
self = value
}
}

Related

Protocol 'Numeric' can only be used as a generic constraint because it has Self or associated type requirements

I have the following swift code that was written by a colleague.
I don't know swift.
I've been running 'Product' -> 'Archive' in xcode so that I can release to the App Store.
The following code has been in place for a long time and I haven't changed it, but I'm now getting the error "Protocol 'Numeric' can only be used as a generic constraint because it has Self or associated type requirements".
Does anyone know what the issue is? ...and could you explain it?
Any help is greatly appreciated.
import Foundation
func MyCallback(_ id: String, _ with: Any?) -> String{
return "My.callback('\(id)', \(with != nil ? with is Numeric ? with! : "'\(with!)'" : "void 0"));"
}
IMO at a glance this code looks really bad. This is not how you unwrap optionals in Swift. Anyway if with is a Numeric type or a String you can simply try to cast it as a String instead of checking if it is Numeric.
func MyCallback(_ id: String, _ with: Any?) -> String {
if let string = with as? String {
return "My.callback('\(id)', '\(string)');"
} else if let with = with {
return "My.callback('\(id)', \(with));"
}
return "My.callback('\(id)', void 0);"
}
Note that it is Swift naming convention to name your methods starting with a lowercase letter func myCallback.

Is there a way in Swift to partially match a generic?

That is, if I have a class C that takes two generics A and B, is there a way where I can cast an object to C where I don't care what B is?
My specific use case is that I need to bridge between NSView functionality and the new SwiftUI in a multi-window, but non-document based application. The problem I am having is, given an NSView, I need to obtain the SwiftUI View that it is managing (in my case a View called ContentView).
Note that I do have a solution, which I include below, but it involves the use of Mirror based reflection and I am wondering if there is a better way, most likely involving the use of as? to cast to a partial match of a generic.
The bridging is done using the NSHostingView hence it should seem that one would just do the following:
if let hostingView = NSApplication.shared.keyWindow?.contentView as? NSHostingView<ContentView> {
// do what I need with 'hostingView.rootView'
}
Unfortunately, NSHostingView.rootView does not return the actual ContentView that I created, it returns a modified version of that view dependant on the modifiers used. (In my case I'm using .environmentObject modifier.) As a result the if statement above never returns true because the type is not NSHostingView<ContentView> but rather NSHostingView<ModifiedContent<ContentView, _bunch_Of_Gobbletygook_Representing_The_Modifiers>>. One way to "solve" the problem is to print out the result of type(of: hostingView) when I create the window, and then change my cast to include the current version of the "gobbledygook", but that is brittle for the following two reasons:
If I change the modifiers, the compiler will not warn me that I need to update the cast, and
Since the "gobbledygook" contains single underscored values, I must assume those are internal details that could change. Hence without my changing any code, an OS update could cause the cast to start failing.
So I have created a solution in the form of the following NSView extension:
extension NSView {
func originalRootView<RootView: View>() -> RootView? {
if let hostingView = self as? NSHostingView<RootView> {
return hostingView.rootView
}
let mirror = Mirror(reflecting: self)
if let rootView = mirror.descendant("_rootView") {
let mirror2 = Mirror(reflecting: rootView)
if let content = mirror2.descendant("content") as? RootView {
return content
}
}
return nil
}
}
This allows me to handle my needs using the following:
private func currentContentView() -> ContentView? {
return NSApplication.shared.keyWindow?.contentView?.originalRootView()
}
... sometime later ...
if let contentView = currentContentView() {
// do what I need with contentView
}
What I would like to know is if there is a way to implement originalRootView without the use of reflection, presumably by allowing a partially specified cast to the ModifiedContent object. For example, something like the following (which does not compile):
extension NSView {
func originalRootView<RootView: View>() -> RootView? {
if let hostingView = self as? NSHostingView<RootView> {
return hostingView.rootView
}
if let hostingView = self as? NSHostingView<ModifiedContent<RootView, ANY>> {
return hostingView.rootView.content
}
return nil
}
}
The problem is what to put for "ANY". I would think some form of Any or AnyObject, but the complier complains about that. Essentially I would like to tell the compiler that I don't care what ANY is so long as the ModifiedContent has RootView as its content type.
Any ideas would be appreciated.
Just to make the results official, the answer is "no" there is no way to partially match a generic as of Swift 5.1.

Extending Optional for all Types except one

In the interest of efficient coding, I was wondering if there is a way to write an extension on Optional for all wrapper types With a declared exception.
In this particular instance, that would be String.
My desired use-case would be as follows:
extension Optional where Wrapped != String {
var asString: String? { return self as? String }
}
I'm getting a whole bunch of compilation errors here, where of course this is not possible.
I want to be able to do this so that I don't see the asString property on String? objects, as there is some redundancy there, of course.
Note: this should be able to be applied to any valid type that Wrapped can take.
extension Optional {
var asString: String? {
guard let unwrapped = self else {
return nil
}
return "\(unwrapped)"
}
}
This solution is only allowed by the language
You can't exclude some classes or protocols in where block.
Example,
let some: Range? = 0..<1
some.asString
"0..<1"

In Swift, can you write an extension which returns a typed instance of the class the extension is on?

This is one of those things that seems simple enough, but doesn't work as you'd expect.
I'm working on a 'fluent/chaining'-style API for my classes to allow you to set properties via functions which can be chained together so you don't have to go crazy with initializers. Plus, it makes it more convenient when working with functions like map, filter and reduce which share the same kind of API.
Consider this RowManager extension...
extension RowManager
{
#discardableResult
public func isVisible(_ isVisible:Bool) -> RowManager
{
self.isVisible = isVisible
return self
}
}
This works exactly as one would expect. But there's a problem here... if you're working with a subclass of RowManager, this downcasts the object back to RowManager, losing all of the subclass-specific details.
"No worries!" I thought. "I'll just use Self and self to handle the type!" so I changed it to this...
extension RowManager
{
#discardableResult
public func isVisible(_ isVisible:Bool) -> Self // Note the capitalization representing the type, not instance
{
self.isVisible = isVisible
return self // Note the lowercase representing the instance, not type
}
}
...but that for some reason won't even compile giving the following error...
Command failed due to signal: Segmentation fault: 11
UPDATE
Doing more research, this seems to be because our code both is in, and also uses, dynamic libraries. Other questions here on SO also talk about that specific error in those cases. Perhaps this is a bug with the compiler because as others have correctly pointed out, this code works fine in a stand-alone test but as soon as the change is made in our code, the segmentation fault shows up.
Remembering something similar with class functions that return an instance of that type, I recalled how you had to use a private generic function to do the actual cast, so I tried to match that pattern with the following...
extension RowManager
{
#discardableResult
public func isVisible(_ isVisible:Bool) -> Self // Note the capitalization
{
self.isVisible = isVisible
return getTypedSelf()
}
}
private func getTypedSelf<T:RowManager>() -> T
{
guard let typedSelfInstance = self as? T
else
{
fatalError() // Technically this should never be reachable.
}
return typedSelfInstance
}
Unfortunately, that didn't work either.
For reference, here's the class-based code I attempted to base that off of (className is another extension that simply returns the string-representation of the name of the class you called it on)...
extension UITableViewCell
{
/// Attempts to dequeue a UITableViewCell from a table, implicitly using the class name as the reuse identifier
/// Returns a strongly-typed optional
class func dequeue(from tableView:UITableView) -> Self?
{
return self.dequeue(from:tableView, withReuseIdentifier:className)
}
/// Attempts to dequeue a UITableViewCell from a table based on the specified reuse identifier
/// Returns a strongly-typed optional
class func dequeue(from tableView:UITableView, withReuseIdentifier reuseIdentifier:String) -> Self?
{
return self.dequeue_Worker(tableView:tableView, reuseIdentifier:reuseIdentifier)
}
// Private implementation
private class func dequeue_Worker<T:UITableViewCell>(tableView:UITableView, reuseIdentifier:String) -> T?
{
return tableView.dequeueReusableCell(withIdentifier: reuseIdentifier) as? T
}
}
At WWDC Apple confirmed this was a Swift compiler issue that something else In our codebase was triggering, adding there should never be a case where you get a Seg11 fault in the compiler under any circumstances, so this question is actually invalid. Closing it now, but I will report back if they ever address it.

Check if a view controller one of few possible types in Swift

Can one use an array of types to refactor the following condition?
vc is ViewController1 || vc is ViewController2 || vc is ViewController3...
YES, but you shouldn't.
You CAN create an array of types:
let types:[Any.Type] = [CGFloat.self, Double.self, Float.self]
You MUST specify the type of the array as [Any.Type]. It can't figure it out on it's own.
You can even get a type from a variable that matches those.
let double = 42.13
double.dynamicType --> Double.Type
types.contains(double.dynamicType) --> true
As #werediver suggests, probably the most swift idiomatic way to do such in swift is to define an empty protocol:
protocol ExaltedViewController { }
and then conform your various classes to it:
extension ViewController1:ExaltedViewController { }
extension ViewController2:ExaltedViewController { }
extension ViewController3:ExaltedViewController { }
Then you can just test with
if vc is ExaltedViewController { ... }
The advantage of doing this is that you don't have to have a centrally managed list. If your code were a framework, where you wanted other peoples view controllers to be added into that list, they could simply adopt the protocol, rather than having to hunt down where the special list was and edit it.
An alternate approach is to use a switch statement with stacked is tests. Consider the following:
func typeWitch(something:Any) { // type divining function
switch something {
case is CGFloat, is Float, is Double:
print("it's got floating point superpowers")
case is Int, is Int16, is Int32, is Int8, is Int64:
print("it's a signed int")
default:
print("it's something else")
}
}
typeWitch("boo")
typeWitch(13)
typeWitch(42.42)
And of course, you can put the two approaches together.
You could make an extension like this:
import Foundation
extension SequenceType where Generator.Element == Any.Type{
func containsType(object:Any)->Bool{
let mirror = Mirror(reflecting: object)
let objectType = mirror.subjectType
return self.contains{objectType == $0}
}
}
And you call it like this:
if [ViewController1.self, ViewController2.self, ViewController3.self].containsType(vc){
//statement is true
}else{
//Statement is false
}
In the documentation here it says This type may differ from the subject's dynamic type when self is the superclassMirror() of another mirror. This is in regards to .subjectType.
One possible way:
let types: [Any.Type] = [CGFloat.self, Double.self, Float.self]
let myVar = 10.0
let isFloat = types.contains { myVar.dynamicType == $0 }
print("Is float: \(isFloat)")
Unfortunately, Swift doesn't allow us to test myVar is $0 directly with dynamic types. Therefore this is not very useful if we want to check subclasses.
I would really recommend the solution with a custom protocol.