CoreEngine

1.1.0

🌪️ Simple and light-weighted unidirectional architecture in Swift which independent of Reactive framework
sobabear/CoreEngine

What's New

Release DidPublished

2024-01-23T13:42:42Z

Added @DidPublisehd

CoreEngine

CI Status Version License Platform

Simple and light

image Core is a framework for making more reactive applications inspired by ReactorKit, Redux.

Scalability

Core is Reactive independent Framework which means you can expand whatever you want to import such as Combine, RxSwift.

It's a very light weigthed and simple architecture, so you can either use CocoaPods or SPM to stay up to date, or just drag and drop into your project and go. Or you can look through it and roll your own.

Installation

CoreEngine is available through CocoaPods. To install it, simply add the following line to your Podfile:

CocoaPods

pod 'CoreEngine'

Swift Package Manager

Swift Package Manager is a tool for managing the distribution of Swift code. It’s integrated with the Swift build system to automate the process of downloading, compiling, and linking dependencies.

To integrate SnapKit into your Xcode project using Swift Package Manager, add it to the dependencies value of your Package.swift:

dependencies: [
    .package(url: "https://github.com/sobabear/CoreEngine.git", .upToNextMajor(from: "1.1.0"))
]

Performance

Screenshot 2023-04-28 at 1 39 26 PM

Core Engine is insanely fast and light-weight compared to similar frameworks you can check details here CoreEngineBenchMark

Example

See details on Example

// on ViewController
 let label = UILabel()
 let increaseButton = UIButton()
 let decreaseButton = UIButton()
 var core: MainCore = .init()
 
 func increaseButtonTapped() {
   self.core.action(.increase)
 }
 
 func decreaseButtonTapped() {
   self.core.action(.decrease)
 }

 func multipleActions() {
   self.core.action(.increase, .decrease)
 }

 
 func bind() {
   core.$state.map(\.count)
       .sink { [weak self] count in
           self?.label.text = "\(count)"
       }
       .store(in: &subscription)
 }
 ...
class MainCore: Core {
    var subscription: Set<AnyCancellable> = .init()
    
    enum Action: Equatable, Hashable {
        case increase
        case decrease
    }
    
    struct State: Equatable {
        var count = 0
    }

    @Published var state: State = .init()

    func reduce(state: State, action: Action) -> State {
        var newState = state
        switch action {
        case .decrease:
            newState.count -= 1
        case .increase:
            newState.count += 1
        }
        return newState
    }
}

Side Effect & Error Handling

Not just simple core, but complex core is also supported. For example, Side Effect and Error handling. When it comes to those, you use AnyCore.

It is not very different from Core, since AnyCore also conforms.

func dispatch(effect: any Publisher) & func handleError(error: Error)

This method is defined in AnyCore and when you deal with side-effect generated publisher send into the function. Also you can handle every errors on the handleError(error: Error) function

Here is an example of the AnyCore

class MainCore: AnyCore {
 var subscription: Set<AnyCancellable> = .init()

 enum Action {
     case increase
     case decrease
     case jump(Int)
     case setNumber(Int)
 }

 struct State {
     var count = 0
 }

 @Published var state: State = .init()
 @Published var tenGap: Int = 10
 
 private let sessionService = SessionService()
 
 init {
     dispatch(effect: sessionService.randomUInt$().map(Action.setNumber))
 }
 
 func reduce(state: State, action: Action) -> State {
     var newState = state
     
     switch action {
     case .increase:
         newState.count += 1
     case .decrease:
         newState.count -= 1
     case let .jump(value):
         newState.count += value
     case let .setNumber(value):
         newState.count = value
     }
     return newState
 }
 
 func handleError(error: Error) {
     if let errpr = error as? MyError {
         //handle
     }
 }
 
 func tenJumpAction() {
     self.dispatch(effect: $tenGap.map(Action.jump))
 } 
}


class SessionService {
 func randomUInt$() -> AnyPublisher<Int, Error> {
 // blahblah
 }
}

Examples + RxSwift

copy those code for RxSwift

import Foundation
import CoreEngine
import RxSwift

protocol RxCore: Core {
    var disposeBag: DisposeBag { get set }
    
    func mutate(effect: Observable<Action>)
    func handleError(error: Error)
}

extension RxCore {
    public func mutate(effect: Observable<Action>) {
        effect
            .subscribe(onNext: { [weak self] in
                if let self {
                    self.state = self.reduce(state: self.state, action: $0)
                }
                
            }, onError: { [weak self] in
                self?.handleError(error: $0)
            })
            .disposed(by: disposeBag)
    }
    
    public func handleError(error: Error) { }
}


@propertyWrapper
class ObservableProperty<Element>: ObservableType {
  var wrappedValue: Element {
    didSet {
      subject.onNext(wrappedValue)
    }
  }
  
  private let subject: BehaviorSubject<Element>
  
  init(wrappedValue: Element) {
    self.wrappedValue = wrappedValue
    self.subject = BehaviorSubject<Element>(value: wrappedValue)
  }
  
  var projectedValue: Observable<Element> {
    return subject.asObservable()
  }
  
  func subscribe<Observer>(_ observer: Observer) -> Disposable where Observer : ObserverType, Element == Observer.Element {
    return subject.subscribe(observer)
  }
}

Author

stareta1202, stareta1202@gmail.com

License

CoreEngine is available under the MIT license. See the LICENSE file for more info.

Description

  • Swift Tools 5.7.0
View More Packages from this Author

Dependencies

  • None
Last updated: Mon Dec 09 2024 18:36:45 GMT-1000 (Hawaii-Aleutian Standard Time)