Using a kotlin clause with enums instead of multiple if - if-statement

I am working with the next code:
override fun presentNativeItem(dcsItem: DCSItem?): Any {
if (dcsItem?.type == "NavMenu") {
return buildNavMenu(dcsItem)
} else if (dcsItem?.type == "NavLink") {
return buildNavLink(dcsItem)
} else if (dcsItem?.type == "Image") {
return buildImage(dcsItem)
}
else throw IllegalStateException("Unknown Type ${dcsItem?.type} of NavItem")
}
But instead of using multiple if, I would like to use the next enum:
enum class DSCType {
NAVMENU,
NAVLINK,
IMAGE;
override fun toString(): String {
return this.name.toLowerCase()
}
companion object {
fun fromString(value: String?): DSCType? {
return when (value?.toLowerCase()) {
"NavMenu" -> NAVMENU
"NavLink" -> NAVLINK
"Image" -> IMAGE
else -> null
}
}
}
}
Any ideas of how can I achieve that in the kotlin way?
Thanks

Make your input parameter not nullable and change your function to:
override fun presentNativeItem(dcsItem: DCSItem) = when(dcsItem) {
NAVMENU -> buildNavMenu(dcsItem)
NAVLINK -> buildNavLink(dcsItem)
IMAGE -> buildImage(dcsItem)
}

try this:
fun presentNativeItem(dcsItem: DCSItem?): Any {
return enumValues<DSCType>().firstOrNull { dcsItem?.type == it.typeName }
?.build(dcsItem)
?: throw IllegalStateException("Unknown Type ${dcsItem?.type} of NavItem")
}
enum class DSCType(val typeName: String) {
NAV_MENU("NavMenu") {
override fun build(dcsItem: DCSItem?): Any {
TODO("not implemented")
}
},
NAV_LINK("NavLink") {
override fun build(dcsItem: DCSItem?): Any {
TODO("not implemented")
}
},
IMAGE("Image") {
override fun build(dcsItem: DCSItem?): Any {
TODO("not implemented")
}
};
abstract fun build(dcsItem: DCSItem?): Any
}

Related

Swift 3 - iterate over generic collection

I have struct Queue<T> that is based on a LinkedList<T>() I want to be able to iterate over the element in the queue and do something with them.
After doing some digging, I believe I have to inherit from Sequence and do something like this:
extension Sequence {
public func makeIterator() -> CountableRange<T>.Iterator {
return (0..<self).makeIterator()
}
}
and after I can have a function in my Queue class something like:
func iter(q: T) -> T? {
for i in q {
}
}
except the extension throws Use of undeclared type 'T' and the for loop a Type 'T' does not conform to protocol 'Sequence'
I am fairly new to Swift and I understand what I have to do I just don't know how to do it and find most explanations quite confusing. Could someone point me in the right direction?
import Foundation
public struct Queue<T> : Sequence{
fileprivate var list = LinkedList<T>()
public var queueCount : Int {
return list.getCount()
}
public var isEmpty: Bool {
return list.isEmpty
}
public mutating func enqueue(_ element: T) {
list.append(value: element)
}
public mutating func dequeue() -> T? {
guard !list.isEmpty, let element = list.first else { return nil }
list.remove(node: element)
return element.value
}
public func peek() -> T? {
return list.first?.value
}
func iter(q: T) -> T? {
for i in q {
}
}
}
extension Queue: CustomStringConvertible {
// 2
public var description: String {
// 3
return list.description
}
}
extension Sequence {
public func makeIterator() -> CountableRange<T>.Iterator {
return (0..<self).makeIterator()
}
}

Swift 3: Convert PromiseKit deferred to RxSwift

I'm currently replacing PromiseKit with RxSwift, and need to convert my deferred promise to RxSwift.
Current implementation example in PromiseKit:
private var deferredDidLayout = Promise<()>.pending()
override func layoutSubviews() {
super.layoutSubviews()
self.deferredDidLayout.fulfill()
}
func setup() {
_ = self.didLayout().then {_ -> Void in
// Do my stuff only one time!
}
}
private func didLayout() -> Promise<()> {
return self.deferredDidLayout.promise
}
Current hack-implementation in RxSwift:
private let observableDidLayout = PublishSubject<Void>()
override func layoutSubviews() {
super.layoutSubviews()
self.observableDidLayout.onCompleted()
}
func setup() {
_ = self.observableDidLayout
.subscribe(onCompleted: { _ in
// Do my stuff only one time!
// Issue: Will be executed on every onCompleted() call
})
}
Thank you in regard!
PromiseKit: https://github.com/mxcl/PromiseKit
RxSwift: https://github.com/ReactiveX/RxSwift
I believe that 'Completable' is what you are looking for - https://github.com/ReactiveX/RxSwift/blob/master/Documentation/Traits.md#creating-a-completable

RxSwift Observable filter with casting

Disclaimer: i'm a half Rx newbie, so it is very possible that the idea is completely bonkers :)
I'm trying to write ObservableType filter, which would pass only certain type, but will pass that type, not the original sequence type. This is what i came up with so far:
extension ObservableType where Self.E: RxFilterableType {
func filterByCast<T: RxFilterableType>(class: T.Type) -> Observable<T> {
let retval = PublishSubject<T>()
self.subscribe { event in
switch event {
case .next(let element):
if let passed = element as? T {
retval.onNext(passed)
}
case .error(let error):
retval.onError(error)
case .completed:
retval.onCompleted()
}
}
return retval
}
}
func test() {
class A: RxFilterableType {}
class B: RxFilterableType {}
let array: [RxFilterableType] = [A(), B()]
let observable: Observable<RxFilterableType> = Observable.from(array)
let observableCasted: Observable<A> = observable.filterByCast(class: A.self)
}
This has two problems: the lesser problem is that the inner subscribe disposable is not taken care of. Ideally i'd like to pass the disposal responsibility onto the return value, but i can take the disposer as parameter. I don't care.
The bigger problem is the compiler objection on the last test line:
Using 'RxFilterableType' as a concrete type conforming to protocol 'RxFilterableType' is not supported
Which means, i'm afraid, that the compiler has not enough informations to infer what i'm trying to do, despite more-than-necessary hints i've added in desperate attempts to help the poor guy.
If you put this in a playground configured to use RxSwift, it will work:
import RxSwift
extension ObservableType {
func filterByCast<T>() -> Observable<T> {
return self.filter { $0 is T }.map { $0 as! T }
}
}
protocol Foo { }
struct A: Foo { }
struct B: Foo { }
let array: [Foo] = [A(), B()]
let observable = Observable.from(array)
let casted: Observable<A> = observable.filterByCast()
_ = casted.subscribe(onNext: { print($0) })
Or if you don't like specifying the type of casted:
extension ObservableType {
func filterByCast<T>(_ class: T.Type) -> Observable<T> {
return self.filter { $0 is T }.map { $0 as! T }
}
}
protocol Foo { }
struct A: Foo { }
struct B: Foo { }
let array: [Foo] = [A(), B()]
let observable = Observable.from(array)
let casted = observable.filterByCast(A.self)
_ = casted.subscribe(onNext: { print($0) })
Requiring the class type as a parameter is a nice touch of yours. I hadn't thought of doing that.

How to simplify long subscription into multiple observers/drivers

How can I transform this (simplified for clarity, if you can believe it)…
override func viewDidLoad() {
super.viewDidLoad()
viewModel.track
.asObservable()
.subscribe(onNext: { upcomingTrack in
self.showLoadingView()
upcomingTrack.fetchYoutubeData()
.observeOn(ConcurrentDispatchQueueScheduler(globalConcurrentQueueQOS: .background))
.subscribe(onNext: { metadata in
if metadata.isInvalid {
viewModel.skip(upcomingTrack)
return
}
XCDYouTubeClient.default().getVideoWithIdentifier(metadata.youTubeId, completionHandler: { (video, error) in
if video != nil {
if let streamUrls = video?.streamURLs,
let streamUrl = streamUrls[NSNumber(value: XCDYouTubeVideoQuality.HD720.rawValue)]
?? streamUrls[NSNumber(value: XCDYouTubeVideoQuality.medium360.rawValue)] {
// πŸƒ DO STUFF WITH streamURL
// πŸƒ DO STUFF WITH upcomingTrack
self.hideLoadingView()
} else {
// ☠️ Not happy about this duplication
viewModel.skip(upcomingTrack)
}
} else {
viewModel.skip(upcomingTrack)
}
})
}).addDisposableTo(self.disposeBag)
}).addDisposableTo(self.disposeBag)
}
…into something like this:
override func viewDidLoad() {
super.viewDidLoad()
viewModel.trackBeganLoading
.drive(onNext: { _ in
self.showLoadingView()
}
viewModel.loadedTrack
.drive(onNext: { upcomingTrack in
// πŸƒ DO STUFF WITH upcomingTrack
self.hideLoadingView()
})
.addDisposableTo(disposeBag)
viewModel.streamURL
.drive(onNext: { url in
// πŸƒ DO STUFF WITH streamURL
})
.addDisposableTo(disposeBag)
}
Apologies in advance for the open-ended nature of this question. I'm not even sure where to start unravelling this beast!

swift 3, PHFetchResult.enumerateObjects error

In swift 3,the method is show me "ambiguous use of 'enumerateObjects'",what happen.how can i do?
extension PHFetchResult {
public func assetCollection() -> [PHAssetCollection] {
var list :[PHAssetCollection] = []
self.enumerateObjects { (object, index, stop) in
if object is PHAssetCollection {
let collection = object as! PHAssetCollection
list.append(collection)
}
}
return list
}
}
Swift 3.0: Just add the Round Brackets before Curly Brackets starts after enumerateObjects.
extension PHFetchResult {
public func assetCollection() -> [PHAssetCollection] {
var list :[PHAssetCollection] = []
self.enumerateObjects ({ (object, index, stop) in
if object is PHAssetCollection {
let collection = object as! PHAssetCollection
list.append(collection)
}
})
return list
}
}
Do something like this noh. You can't directly add extension for PHFetchResult because it has other ObjectType as its generic parameter PHFetchResult<ObjectType> . So you must do something else.
class FetchPhoto {
class func assetCollection() -> [PHAssetCollection] {
var list :[PHAssetCollection] = []
PHAssetCollection.fetchMoments(with: nil).enumerateObjects(EnumerationOptions.concurrent) { (collection, _, _) in
list.append(collection)
}
return list
}
}
PHAssetCollection.fetchMoments returns PHFetchResult<PHAssetCollection> here PHAssetCollection is the ObjectType for the PHFetchResult. You got the ambiguous error because you have not specified the objectType.
A generic way to approach this.
class FetchPhoto {
class func assetCollection<T : PHObject>(result : PHFetchResult<T>) -> [T] {
var list : [T] = []
result.enumerateObjects(EnumerationOptions.concurrent) { (object, _, _) in
list.append(object)
}
return list
}
}
Swift 3
class PhotosHelper {
class func fetchAllLocalIdentifiersOfPhotos(completion : (_ localIdentifiers : [String]) -> ()) {
let photos : PHFetchResult<PHAsset> = PHAsset.fetchAssets(with: PHAssetMediaType.image, options: nil)
photos.enumerateObjects ({ _,_,_ in
// Do your operations, you can see that there is no warnings/errors in this one
})
}
}