Can I do something not `transfrom` in `map` and `flatMap` function? - swift

Is Map function of Optional in Swift just used to transform?
If I want do something just Optional has some value, Can I Use map function? if not, why?
According to apples examples, we used map like this
let possibleNumber: Int? = Int("42")
possibleNumber.map { $0 * $0 }
Can I use it like this? : (If it's not proper, how to explain it)
func setImage(with data: Data?) {
data.flatMap { UIImage(data: $0) }
.map { imageView.image = $0 }
}
Furthermore map function should return a value, but why this function does not have any warning about not used of result ( such as result of call map{...} is unused ) ?

You certainly can do it, it's just not very conventional. When people see map, they have a pre-conceived expectation that it'll be doing a transformation. You're violating that expectation, but there's nothing technically "wrong" about it.
Personally, I prefer using this extension:
extension Optional {
/// An enum used to ensure that `ifNone` is never called before `ifSome`.
enum IfSomeResult {
case some
case none
func ifNone(_ closure: () throws -> Void) rethrows -> Void {
switch self {
case .some: return
case .none: try _ = closure()
}
}
}
#discardableResult
func ifSome(then closure: (Wrapped) throws -> Void) rethrows -> IfSomeResult {
if let wrapped = self {
try _ = closure(wrapped)
return IfSomeResult.some
}
else {
return IfSomeResult.none
}
}
func ifNone(then closure: () throws -> Void) rethrows -> Void {
if case nil = self { try _ = closure() }
}
}
And writing code like:
data.flatMap { UIImage(data: $0) }
.ifSome { imageView.image = $0 }
Why doesn't it warn about an unused value?
The closure is inferred to return Void (the empty tuple type, whose only value is the empty tuple, ()). The compiler never emits warnings about Void values being unused`. Here's an example:
Optional(123).map { _ in () }

Related

Swift Extension - Optional

I'm trying to extend optionals into something readable, and achieved this so far:
#discardableResult
func isNotNil(_ handler: (Wrapped) -> Void) -> Optional {
switch self {
case .some(let value):
handler(value)
return self
case .none:
return self
}
}
#discardableResult
func isNil(_ handler: () -> Void) -> Optional {
switch self {
case .some:
return self
case .none:
handler()
return self
}
}
So that I can call my functions on an optional such as:
viewModel?.title.isNotNil { _ in
//do something
}.isNil {
//handle error
}
The problem is, I want to reuse these functions to return specific types, which I'm not able to achieve or am missing something out. For example:
let vm: MyViewModel = dataSource?.heading.isNotNil {
return MyViewModel(title: $0.title, subtitle: $0.subtitle)
}
I've been brainstorming on this and would love some help around this.
Thanks!
What you're doing in your example will raise errors. It boils down to
let vm: MyViewModel
if let heading = dataSource?.heading {
_ = MyViewModel(heading.title, heading.subtitle)
vm = heading
}
So you're trying to assign heading to vm (which I am assuming are of different types) and you just construct and drop the MyViewModel you construct in the closure
What would be a better option is something along these lines:
func mapOptionalOrNot<T>(notNil: (Wrapped) -> T, isNil: () -> T) -> T {
switch self {
case .some(let value):
return notNil(value)
case .none:
return isNil()
}
}
And you could of course give both function default arguments so you can leave them out.
With Swift 5.3s new multi closures you could do something like
let vm: MyViewModel = dataSource?.heading.mapOptionalOrNot { value in
// Map if we have a value
return MyViewModel(title: value.title, subtitle: value.subtitle)
} isNil: {
// Map if we don't have a value
return MyViewModel(title: "Empty", subtitle: "Empty")
}
Optional is generic and has an associated type that you can use in your extensions as well. It is called Wrapped.
Here is some sample code that you can paste into a Playground:
import UIKit
extension Optional {
#discardableResult
func isNil(_ handler: () -> Void) -> Wrapped? { // <-- We are returning Wrapped, wich is a generic concrete type
switch self {
case .some:
return self
case .none:
handler()
return self
}
}
}
let str: String? = nil
// The function is used and the return value is assigned to the variable handled
let handled = str.isNil {
print("Handling nil value")
}
print(type(of: handled))
// Prints "Optional<String>
Please also note that that what you are trying to build already exists mostly: https://developer.apple.com/documentation/swift/optional/1539476-map
You should probably just used Swift's map instead of your own implementation.

Optional extension for any types

I want to write Optional extension for any types.
My code for integer:
extension Optional where Wrapped == Int {
func ifNil<T>(default: T) -> T {
if self != nil {
return self as! T
}
return default
}
}
var tempInt: Int?
tempInt.ifNil(default: 2) // returns 2
tempInt = 5
tempInt.ifNil(default: 2) // returns 5
It works but it is Optional(Int) extension (Optional where Wrapped == Int), I want to use this extension for any types like Date, String, Double etc.
What are your suggestions?
The answer to your basic question is to just remove the where clause:
extension Optional {
// ... the rest is the same
func isNil<T>(value: T) -> T {
if self != nil {
return self as! T
}
return value
}
}
Now it applies to all Optionals.
But this code is quite broken. It crashes if T is not the same as Wrapped. So you would really mean a non-generic function that works on Wrapped:
extension Optional {
func isNil(value: Wrapped) -> Wrapped {
if self != nil {
return self! // `as!` is unnecessary
}
return value
}
}
But this is just an elaborate way of saying ?? (as matt points out)
extension Optional {
func isNil(value: Wrapped) -> Wrapped { self ?? value }
}
Except that ?? is much more powerful. It includes an autoclosure that avoids evaluating the default value unless it's actually used, and which can throw. It's also much more idiomatic Swift in most cases. You can find the source on github.
public func ?? <T>(optional: T?, defaultValue: #autoclosure () throws -> T)
rethrows -> T {
switch optional {
case .some(let value):
return value
case .none:
return try defaultValue()
}
}
But I can imagine cases where you might a method-based solution (they're weird, but maybe there are such cases). You can get that by just rewriting it as a method:
extension Optional {
public func value(or defaultValue: #autoclosure () throws -> Wrapped) rethrows -> Wrapped {
switch self {
case .some(let value):
return value
case .none:
return try defaultValue()
}
}
}
tempInt.value(or: 2)
Optional is already a generic. It already takes any type as its parameterized type. Its parameterized already has a name: Wrapped. Just say Wrapped instead of T. Your T is Wrapped.
extension Optional {
func isNil<Wrapped>(value: Wrapped) -> Wrapped {
if self != nil {
return self as! Wrapped
}
return value
}
}
If you really prefer T for some reason, use a type alias. It's only a name:
extension Optional {
typealias T = Wrapped
func isNil<T>(value: T) -> T {
if self != nil {
return self as! T
}
return value
}
}
But in any case your extension is completely unnecessary because this is what the nil-coalescing operator ?? already does.
var tempInt: Int?
tempInt ?? 2 /// returns 2
tempInt = 5
tempInt ?? 2 /// returns 5

How to create a closure to return which one of the parameters is true?

I need to create some sort of closure to return back if it's an optional or forced update. I've created some pseudo code:
func verifyAppVersionWithServer(isForceUpdate: bool -> true, isOptionalUpdate: bool -> true) {
//Some check will be performed here then:
if isForceUpdate {
return isForceUpdate -> true
} else {
return isOptionalUpdate -> true
}
}
I'm not sure how to create a closure in Swift which will then return which of the parameters is true.
It is probably nicer to return an enum that indicates the type of update required.
You would then have something like this:
enum UpdateType {
case None
case Optional
case Required
}
func verifyAppVersionWithServer(completion:(UpdateType) -> Void) {
let anyUpdate = true
let forcedUpdate = false
if anyUpdate {
if forcedUpdate {
completion(.Required)
} else {
completion(.Optional)
}
} else {
completion(.None)
}
}
You would call it as:
verifyAppVersionWithServer { (updateType) in
print("Update type is \(updateType)")
}
Obviously the values would be determined by your server response, not fixed values as I have shown.
You can use something like below
func verifyAppVersionWithServer(parm1: String, withParma2: Bool, completionHandeler: (isSucess: Bool, error : NSError) -> Void) {
//Write your logic
//call complition handeler
completionHandeler(isSucess: true, error: error)
}
Hope this will help

Extending SignalProducerType in case Value is an Array<SomeProtocol>

I have a protocol for fetching database objects by PrimaryKey
typealias PrimaryKey = String
protocol PrimaryKeyConvertible {
var pkValue : PrimaryKey { get }
static func pkObject(key: PrimaryKey) -> Self?
}
and I want to extend the SignalProducerType to be able to operate on a SignalProducer.Value of that type.
So the Single object extension (single as in not Array) works fine and implemented as following:
extension SignalProducerType
where Value: PrimaryKeyConvertible
{
func fetchOnMainThread() -> SignalProducer<Value?, Error> {
return
self.map{ (obj: Value) -> PrimaryKey in
return obj.pkValue
}
.observeOn(UIScheduler())
.map{ (key: PrimaryKey) -> Value? in
return Value.pkObject(key)
}
}
}
But when I try to implement it on an Array of these elements i hit some compilation challenges:
extension SignalProducerType
{
func fetchOnMainThread<P: PrimaryKeyConvertible where Self.Value == Array<P>>() -> SignalProducer<[P], Error> { //(1)
return self.map({ (value: Self.Value) -> [PrimaryKey] in
return value.map{ $0.pkValue } //(2)
})
}
}
(1) i suspect that the signature is not communicating the idea to the compiler correctly
(2) produces the following error:
Type of expression is ambiguous without more context
the issue i'm trying to solve is how to let the compiler recognize the the SignalProducer is operating on an Array<P> where P is PrimaryKeyConvertible and have the .map operate on it accordingly ...
my current solution for the array issue is to implement using a generic function as listed below:
func fetchOnMainThread<Value: PrimaryKeyConvertible, Error: ErrorType>
(signal: SignalProducer<[Value], Error>) -> SignalProducer<[Value], Error> {
return signal
.map{ (convertibles: [Value]) -> [PrimaryKey] in
return convertibles.map { $0.pkValue }
}
.observeOn(UIScheduler())
.map{ (keys: [PrimaryKey]) -> [Value] in
return keys.flatMap{ Value.pkObject($0) }
}
}
and then used for example:
extension GoogleContact: PrimaryKeyConvertible {...}
extension GoogleContact {
static func fetchGoogleContactsSignal() -> SignalProducer<[GoogleContact], GoogleContactError> { ...}
}
and the call site would be like:
let signal = fetchOnMainThread(GoogleContacts.fetchGoogleContactsSignal()).onNext...
where I would prefer to have it as an extension where it would flow as usual
GoogleContacts
.fetchGoogleContactsSignal()
.fetchOnMainThread()
Update
another version of the function I've tried : (#J.Wang)
extension SignalProducerType
where Value == [PrimaryKeyConvertible]
{
func fetchArrayOnMainThread2<T: PrimaryKeyConvertible>() -> SignalProducer<[T], Error> {
return self
.map{ (values: Self.Value) -> [PrimaryKey] in
return values.map{ $0.pkValue }
}
.deliverOnMainThread()
.map{ (keys: [PrimaryKey]) -> [T] in
return keys.flatMap{ T.pkObject($0) }
}
}
}
let signal =
GoogleContacts
.fetchGoogleContactsSignal()
.fetchArrayOnMainThread2() //(3)
(3) Generates error:
'[PrimaryKeyConvertible]' is not convertible to '[GoogleContact]'
Hmm, although I'm not quite sure what the problem is, but I think the following implementation might be what you want.
extension SignalProducerType where Value == [PrimaryKeyConvertible]
{
func fetchOnMainThread() -> SignalProducer<[PrimaryKey], Error> {
return self.map { value in
value.map { $0.pkValue }
}
}
}
Try this:
extension SignalProducerType where Value == [PrimaryKeyConvertible]
{
func fetchOnMainThread<T: PrimaryKeyConvertible>() -> SignalProducer<[T], Error> {
return self.map { value in
value.map { $0.pkValue }
}.map { keys in
keys.flatMap { T.pkObject($0) }
}
}
}

Swift generics: return type based on parameter type

Say I have a collection of objects inheriting from a common superclass (this is preferable to protocols in this case):
class ObjectSuperClass {
type: ObjectType
}
class ObjectClass1: ObjectSuperClass {
type = .Type1
}
class ObjectClass2: ObjectSuperClass {
type = .Type2
}
I'm looking to create a generic search function like this:
func objectsOfType<T: ObjectSuperClass>(T.class, otherFilter: Any?) -> [T]
Which could be used to search for a given sub-type, returning a more specific array of results:
let result = objectsOfType(ObjectClass2.class, otherFilter: nil) -> [ObjectClass2]
(pseudo-swift)
I feel like this is somewhere generics could help, but cannot see where constraints should be placed. Is it possible?
Well remarkably this works...
func filterType<T>(list: [AnyObject]) -> [T]
{
return list.filter{ $0 is T }.map{ $0 as! T }
}
...provided you assign the result to something that has been explicitly typed, as in the following example:
class ObjectSuperClass: CustomStringConvertible
{
let myType: String
init(aString: String)
{
myType = aString
}
var description: String { return myType }
}
class ObjectClass1: ObjectSuperClass
{
init()
{
super.init(aString: "<t 1>")
}
}
class ObjectClass2: ObjectSuperClass
{
init()
{
super.init(aString: "<t 2>")
}
}
let unfilteredList: [AnyObject] = [ ObjectClass1(), ObjectClass2(), ObjectSuperClass(aString: "<Who knows>")]
let filteredList1: [ObjectClass1] = filterType(list: unfilteredList)
print("\(filteredList1)") // <t 1>
let filteredList2: [ObjectClass2] = filterType(list: unfilteredList)
print("\(filteredList2)") // <t 2>
let filteredList3: [ObjectSuperClass] = filterType(list: unfilteredList)
print("\(filteredList3)") // [<t 1>, <t 2>, <Who knows>]
T is inferred in each case from the requested return type. The function itself filters the original array based on whether the elements are of the required type and then force casts the filtered results to the correct type.
If you want an "extra filter" you don't need to explicitly type the results as long as T can be inferred from your extra filter function.
func extraFilterType<T>(list: [AnyObject], extraFilter: T -> Bool) -> [T]
{
return list.filter{ $0 is T }.map{ $0 as! T }.filter(extraFilter)
}
let filteredList = extraFilterType(unfilteredList){
(element : ObjectClass2) -> Bool in
!element.description.isEmpty
}
print("\(filteredList)") // <t 2>
EDIT
A slicker version of the filterType function would use flatMap()
func filterType<T>(list: [Any]) -> [T]
{
return list.flatMap{ $0 as? T }
}
EDIT 2
Flatmap is deprecated for optionals, since Swift 4.something, use compactMap
func filterType<T>(list: [Any]) -> [T]
{
return list.compactMap{ $0 as? T }
}
This is the closest approximation I can come up with:
func objectsOfType<T: ObjectSuperClass>(type type: T.Type) -> [T] {
// Just returns an array of all objects of given type
}
func objectsOfType<T: ObjectSuperClass>(type type: T.Type, predicate: T -> Bool) -> [T] {
// Uses predicate to filter out objects of given type
}
Usage:
let bar = objectsOfType(type: ObjectClass1.self)
let baz = objectsOfType(type: ObjectClass2.self) {
// Something that returns Bool and uses $0
}
Technically, you can also go without type argument in the above, but then you will need to have explicitly typed receivers (bar and baz in the above example) so that Swift can correctly infer the types for you and use the right version of the generic function.
You can implement the function like this:
func objectsOfType<T: ObjectSuperClass>(objects: [ObjectSuperClass], subclass: T.Type, otherFilter: (T->Bool)?) -> [T] {
if let otherFilter = otherFilter {
return objects.filter{$0 is T && otherFilter($0 as! T)}.map{$0 as! T}
} else {
return objects.filter{$0 is T}.map{$0 as! T}
}
}
Usage example:
objectsOfType(arrayOfObjects, subclass: ObjectClass1.self, otherFilter: nil)
Note that I'm not a fan of forced casting, however in this scenario it should not cause problems.
Or, the more verbose version of the function, with one less forced cast:
func objectsOfType<T: ObjectSuperClass>(objects: [ObjectSuperClass], subclass: T.Type, otherFilter: (T->Bool)?) -> [T] {
return objects.filter({object in
if let object = object as? T {
if let otherFilter = otherFilter {
return otherFilter(object)
} else {
return true
}
} else {
return false
}
}).map({object in
return object as! T
})
}