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