막 쓰지만... 누군가에겐 도움이 되겠지 하고 또 일정 기간 동안 올려본다.(구독자들은 알겠지만 그냥 지울 때도 있고 블로그로 올릴 때도 있다. 순수하게 떠들고 싶은 마음으로 쓰는 경우라...)


리액티브, Redux, 패턴 이야기를 해 볼까 한다. 내용은 구리다. 나는 바쁘니까.

그래도 정말 삽질하지 말라고 하고 싶다. 이미 제품을 만든 다른 사람이 이야기를 좀 해줬으면 좋겠다. 네가 한 말이 틀렸다고. 너무 제품에만 집중해서 시간을 보내다 보니(정치/사회도 관심이 많아서) 정말 맥북 모니터만 뚫어져라 보는 것 같다. 최근 하이와 여행 때도 밤에는 늘 노트북만 쳐다보고, 행사 있을 때마다 맥북을 들고 다녔다. ㅠ 너무 바쁘면 시야가 좁아진다. 그래서 누가 틀렸다고 이야기해줬으면 좋겠다는 말이다. 브런치의 자동 수정 기능을 믿고 그냥 클릭만 할 거기에 이상한 게 있어도 지적 바란다.


프로젝트를 3개 진행 중이다. 모두 돈을 받는 일이다.


1. 우선, react 하지 마라. 망한다. 간단한 앱 만드는 것은 괜찮은데 IoT 들어가거나 코어 그래픽 들어가면 쓰지 마라. 왠지 설계자가 개발자 출신이 아니라면 그냥 처음부터 쓰지 마라.


2. 리액티브 처음에는 괜찮은데 프로젝트 커지면 오히려 디버깅이 안된다. 적당한 프로젝트에 쓰길 바란다.


3. Reswift는 좋다. 마음껏 써라. 프로젝트 하나는 그걸 쓴다. 그런데 패턴으로도 구현 가능하다. 내가 썼던 글...(더블 클로저)로 구현해도 되는데 프로젝트 커지면 가독성 떨어지는 게 사실이다. 그럴 때 GS.swift, BR.swift를 만든다. 


브로드 캐스트를 담당하는 BR.swift 는 이런 형태다. 뭐, 이미 다 말했지만... 정말 개발 해보니 이거면 되서 ... 다시 쓴다.


import UIKit


//MARK: protocols titled by weird name to find related modules easily. -hjh-

protocol gamcho {

    func updateText()

}


protocol trendpopup {

    func updateText()

}


protocol snowboard {

    func updateGraph()

}


class BR {


    static let s = BR()


    var BRtendency3 dots = [gamcho]()

    var BRtrendpopup = [trendpopup]()

    var BRsnowBoard = [snowboard]()


    private init() {

    }


    func attachBRtendency3 dots(observer : gamcho) {

        BRtendency3 dots.append(observer)

    }


    func attachBRtrendpopup(observer : trendpopup) {

        BRtrendpopup.append(observer)

    }


    func attachBRdashboard(observer : snowboard)  {

        BRsnowBoard.append(observer)

    }




    //MARK: notify to update    BR_ prefix

    func BR_snowBoard(andThis : ()->()) {

        if(GS.s.bSemaphore) {

            GS.s.bSemaphore = false

            for woman in self.BRsnowBoard {

                woman.updateGraph()

            }

            GS.s.bSemaphore = true

        } else {

            print("Busy")

        }

        andThis()

    }


    func BR_tendency3 dots() {

        for homme in self.BRtendency3 dots {

            homme.updateText()

        }

    }


    func BR_trendpopup() {

        for woman in self.BRtrendpopup {

            woman.updateText()

        }

    }

}


글로벌 세팅인 GS.swift는 이런 형태

class GS {


    static let s = GS()


    var bSemaphore : Bool = true

    let queue = DispatchQueue(label: 


.

.

  var lp1 : InsidePanel? = nil

    var rp1 : InsidePanel? = nil

    var lp2 : InsidePanel? = nil

    var rp2 : InsidePanel? = nil

.

.

    func elapsedTime() -> TimeInterval {

        return abs(self.startTime.timeIntervalSinceNow)

    }

.

.

   private init() {

                logLevel =. all


.

.

.


특이한 것은 내가 안드로이드 할 때도 항상 싱글톤은 하나 놔두고 status를 저장하고 썼었다. 삼성에서 안드로이드 프레임웍 만들 때 큐와 BR 구조를 짜다 보니 객체를 등록하고 for 문을 돌면서 메시지를 보내는 BR 구조(옵서버 패턴+ for 문)에 대해 알게 되고 그 이후로는 무조건 썼는데. 나중에 리액티브라는 것을 접하니 큐와 구독(옵저BR구조)에 스케쥴러까지 결합한 형태라는 것을 알게 되었다. 이게 본인이 직접 안 짜고 라이브러리의 힘을 빌면 다양한 디바이스와 커뮤니케이션에서 디버깅이 제대로 될까 했는데... 아니나 다를까 개고생을 해야 했다. 라이브러리는 정말 기본적으로 도와주는 것만 써야 한다고 생각했다. 깃 헙을 보면 reacrokit 보다 snapkit에 star에 10배가 많은 것도 그 이유겠다. 물론, 만든 분을 좋아하긴 하지만... 오래도록 RTOS 프로젝트와 커널을 했던 나로서는 앱 단에서 구현된 스케쥴러가 그리 반갑지는 않다. 프로세스 자체도 운영체제 때문에 오차가 생기는데 그 위에 도는 스레드는 또 어떻고 그 스레드 위에서 도는 앱이 구현하는 스케쥴러도 어쩌리... 펌웨어 하다 보면 라즈베리 파이임에도 불구하고  POSIX 타임 틱도 구려서 커널 time 함수도 그때그때 다시 만드는 상황에... 말이다.(저번 에트리 강의 때 시그널 제작했었는데 time 함수 다시 짰다 [내가 강사임...])


믓튼, iOS 기준으로 일전에는 노티피게이션센터를 썼는데 클러저 덕분에 REST API 동기화는 쉬웠고, 프로그램 전역에는 BR.swift 하나면 충분했다. MVP, MVVM, MVC에 싱글톤과 BR 가능한 옵서버 패턴을 붙이면 두려울 게 없었다. 다만... ReSwift의 경우 데이터 흐름을 고려했다는 점에서 새롭게 도입해서 프로젝트를 잘 마무리하게 되었다.


BadgeSwift, SnapKit, JTAppleCalendar, SwiftNotification, SwiftMessages, lottie-ios  등 UI 라이브러리를 마음대로 써도 된다. View에만 영향을 미치니까. REST는 Alamofire 가 최고다. Pitaya 쓰면 분산되는데 알라모퐈여 쓰면 클해스 하나에 REST를 몰아넣을 수 있다. 막일 방지해주는 SwiftDate, FileKit, SQLiteSwift3, SwiftKeychainWrapper, SwiftyJSON 등 좋다. Firebase 같이 무조건 쓸 수밖에 없는 라이브러리를 제외하고는 SwiftLint, ReSwift 추천한다. 그래프 라이브러리 성능 보니 믿음이 안 가서(프로젝트에서 원하는 성능으로 커스터마이징 하려고) 만들었더니 프로젝트의 1/4을 차지한다. 거대해졌지만 이렇게 커도 GS, BR로 충분하다. 물론, 하나에 다 때려 넣으면 너무 커져서 GV(Global Variable), VD(Volatile Datas) 등으로 이원화해서 쓰기도 했다. 

 하드웨어 제어하는 IoT 기능(BLE, WiFi, socket.io) 코어 그래픽 라이브러리와 위에 언급한 라이브러리 등을 다 넣어도 데이터 꼬임 없는 산출물이 나왔다.


그냥... 카톡만큼 크진 않지만  3개 돈 받는 거 말고 전자 지갑도 만들어 보고(블로그에도 올림) 텔레그램도 하고 있으니 카톡만큼 키우는 게 어렵진 않을 것 같다.


따로 하는 게임이 잘돼서 빠른 시일 내에 법인이 만들어지면 좋겠다.



추가... 내가 쓰는 옵셔널 코드조각



self.vDashboard?.center = tempt

---

static func worldLine(context : CGContext?, _ x1 : CGFloat, 


---

class jhGraphBuilder<T> {

    private var superScene : T?


---

print("ctime in jhType22graphPanel<T> = ", (self.superScene as? jhSceneTimeLine)?.currentTime)


---

class jhPanel<T> : jhDraw, observer_p {

    

    internal var superScene: T?


---

    internal var mAllofCountOfDatas : Int {

        get {

            return eoDataCenter.eoDatasDashboard[jhPanelID]?.d.count ?? 0

        }

    }



---

class jhGuideLine : CALayer {

    

    var layer_size : CGSize = CGSize.init(width: 0, height: 0)

    var lineX : CGFloat

    var lineY : CGFloat

    var lineWidth : CGFloat

    

    init?(x: CGFloat, y: CGFloat, lineWidth: CGFloat, layer:Any) {

        if GS.s.logLevel.contains(.graph2) { print("jhGuideLine_init") }



---

        for woman in 0..<4 {

            for man in 0..<(jhDatas[woman]?.d.count ?? 0) {


---

            ctime = (self.superScene as? jhSceneTimeLine)?.currentTime ?? Date()

            etime = (self.superScene as? jhSceneTimeLine)?.endTime ?? Date()


---

        guard var jhDatas : [Int : hjh] = eoDataCenter.eoDatasDashboard else {

            print("currentPoint.x", currentPoint.x)

            fatalError("guard var jhDatas : hjh = eoDataCenter.mDatas[0] else {")

        }


---

        scene!.createPanels(s: scene!, withHeightRatios: ratioNtype(ratio: 5.10, type: graphType.TYPE1), ratioNtype(ratio: 2.93, type: graphType.TYPE2), ratioNtype(ratio: 1.96, type: graphType.TYPE3))



---


    override func createPanels(s : jhScene, withHeightRatios: ratioNtype...) {

        

        var panel : jhPanel<jhSceneTimeLine>? = nil



---

   panel = jhGraphBuilder<jhSceneTimeLine>()

                .type(rnt.type)

                .frame(0, GS.s.jhSceneHeight!, jhSceneFrameWidth*4, vHeight)

                .scene(self)

                .build()



보너스 삼항연산자


            let xOffset = contentSize.width < bounds.width ? 0 : (contentSize.width - bounds.width)/2


+ Recent posts