반응형

 Claude AI 를 이용해 Tuist를 공부하려고 봤더니... Tuist 설치 부터가 최신 자료가 아니였다.... (쿨럭)

그래서 현재 SKT 회선을 보유한 나로써는 병행해서 사용 하고 있는 Perplexity 서비스를 이용해 보았다.

일단...... 먼저 말하면.... 잘못된 정보? 라고 하기 애매한 ...

암튼 설치 하다 삽질을 더 했다. Tuist 라이브러리 설치에만 무려 오랜 시간이 소요 되었다. 

심지어... 예전 Tuist 설치 방식을 계속 알려주고 있었다... (이건 서비스 로직에 사소한 버그가 있지 않나.... 의심스럽다.) 

Brew 방식으로 설치하라고 해서 설치했다가..... ---> 삭제

RTX 방식으로 설치하라고 해서..... 설치 했다가 ----> 삭제 

그래서 물어봤다.

와........ 진심 화가나기 시작 하였다.... 

 

mise 라는걸 이용해서 설치하란다..... 근데...... 이상하게....... 2번 부터 안되었다... ( 하.... 머지...)

머지?........ 하아... 이때 부터 갑자기 쌔함이......... 

다음과 같은 과정을 진행했다.

 

먼가 잘되는거 같아 보였는데....

그리고 다음과 같은 일련의 과정을 해보니........

 

와........ 역시나..... 쌔한 기운은.... 어디 많이 못간다..... 

Tuist 명령어가 안되기 시작..... 

또 다시... 물어보고....

(과정은 생략했다...)

또 안되서 또 다음과 같이 물어보고...

 

하라는 해도 상황이 똑같다.... ㅋㅋㅋ

또 물어보았다...

(과정 또 생략....)

역시나 문제가 또 발생 다시 또 물어봄...

(과정은 역시나 생략.... , 왜나고? 똑같아서...)

머 당연히 문제 해결은 안되었기에...

과정은..... 또........  생략... 

 

그리고........ 

 

이쯤 되면........ 이제 누가 이기는지 해보자고 전투 모드로 전환....

역시나 또 안.... 되는...

열심히 알려주는데.... 먼가 내용이 똑같은? 게 많다.... 

하라는대로 해보니... 역시나 문제가 발생.... 또 물어봤다!

아니나 다를까.... 안된다. ... .(쿨럭 )

삽질을 통해서... 결국.... 되었다.

 

그래서..... tuist로 프로젝트가 생성되는지도 알아보았다. 

와.... 여기까지 하니... 새로운 문제가... 

(예전에는 구글을 뒤졌다면 지금은.... perplexity에게 물어본다. )

그래서 또 물어보았다...  

그러고 나서.... 궁금한게 생각나서 추가 질문을 하였다.

이렇게 해서......Tuist를 설치 했다.....

그리고 프로젝트 파일도 만들었더니.........

나는 만든 프로젝트가 UIKit 기반일줄 알았는데...... 

swiftui가 기본이였다....  ( 쿨럭 )

그래서 또 물어보았다...

 

 

그랬던 것이였다... 

다음 시간에는 UIkit 기반으로 만들어 봐야 겠다.

반응형
Posted by onlyTheOne
,
반응형

claude로 어떻게 공부를 할 수 있을까 궁금해서 기존에 필터 앱을 업데이트 하고자 다음과 같이 요청 하였습니다. 

"새로운 질문을 하지 swift 언어로 iOS 15 이상에서 카메라앱을 만들거야 동영상 촬영 앱이고 기능은 다음과 같아 1. 동영상 촬영 버튼을 누르면 촬영이 되고 10초뒤에 촬영이 자동 종료 되 2. 동영상 필터는 2개가 제공될거야 3. 필터는 흑백하고 카툰 필터 4. 녹화된 영상은 앱내에 저장하는데 사진앱으로 내보내기 기능을 제공 5. 녹화사에는 전면 카메라 녹화나 후면 카메라 녹화 둘중 하나만 되게 할거야 6. 고급 카메라는 PIP 기능으로 영상이 녹화되게 할거야 7. 카메라 촬영중에는 화면에서 10초 타이머가 보여지면서 촬영된 영상이 실시간으로 보이게 할거야 여기까지 "

이렇게 요청 하니 CIFilter 기반 이 나왔다.....

CIFilter로는 퍼포먼스가 안나오는걸 알고 있기에... 다시 요청 했다.

"아 미안해... metal framework로 구현해줘 CIFilter는 퍼포먼스 안나와"

다음과 같이 안내해 주었다.

코드를 보니.... 분류가 안되어 있어 재차 요청 했다.

"파일명 별로 구분좀 해줄 수 있을까?"

 

위와 같이 프로젝트 구조도 알려주었다. 

 

그래서 각각의 소스코드는 다음과 같다. 

// MARK: - Models/ShaderTypes.swift
struct Vertex {
    var position: SIMD3<Float>
    var textureCoordinate: SIMD2<Float>
}

enum FilterType {
    case normal
    case grayscale
    case cartoon
}

// MARK: - Shaders/CameraShaders.metal
"""
#include <metal_stdlib>
using namespace metal;

struct VertexIn {
    float3 position [[attribute(0)]];
    float2 textureCoordinate [[attribute(1)]];
};

struct VertexOut {
    float4 position [[position]];
    float2 textureCoordinate;
};

vertex VertexOut vertexShader(uint vertexID [[vertex_id]],
                             constant VertexIn *vertices [[buffer(0)]]) {
    VertexOut out;
    out.position = float4(vertices[vertexID].position, 1.0);
    out.textureCoordinate = vertices[vertexID].textureCoordinate;
    return out;
}

fragment float4 fragmentShader(VertexOut in [[stage_in]],
                             texture2d<float> texture [[texture(0)]],
                             constant int &filterType [[buffer(1)]]) {
    constexpr sampler textureSampler(mag_filter::linear,
                                   min_filter::linear);
    
    float4 color = texture.sample(textureSampler, in.textureCoordinate);
    
    // Normal
    if (filterType == 0) {
        return color;
    }
    // Grayscale
    else if (filterType == 1) {
        float gray = dot(color.rgb, float3(0.299, 0.587, 0.114));
        return float4(gray, gray, gray, color.a);
    }
    // Cartoon
    else if (filterType == 2) {
        float3 original = color.rgb;
        
        float2 texelSize = float2(1.0 / texture.get_width(),
                                1.0 / texture.get_height());
        
        float3 edge = float3(0.0);
        for(int i = -1; i <= 1; i++) {
            for(int j = -1; j <= 1; j++) {
                float2 offset = float2(float(i), float(j)) * texelSize;
                float3 sample = texture.sample(textureSampler,
                                            in.textureCoordinate + offset).rgb;
                edge += abs(sample - original);
            }
        }
        
        float3 quantized = floor(original * 5.0) / 5.0;
        float edgeMask = 1.0 - smoothstep(0.2, 0.3, length(edge));
        return float4(quantized * edgeMask, color.a);
    }
    
    return color;
}
"""

// MARK: - Controllers/MetalCameraController.swift
class MetalCameraController: NSObject {
    private var captureSession: AVCaptureSession?
    private var videoOutput: AVCaptureMovieFileOutput?
    private var textureCache: CVMetalTextureCache?
    
    private let metalDevice: MTLDevice
    private let metalCommandQueue: MTLCommandQueue
    private let pipelineState: MTLRenderPipelineState
    private let vertexBuffer: MTLBuffer
    
    private var currentFilterType: FilterType = .normal
    
    private let vertices: [Vertex] = [
        Vertex(position: SIMD3<Float>(-1, -1, 0), textureCoordinate: SIMD2<Float>(0, 1)),
        Vertex(position: SIMD3<Float>(1, -1, 0), textureCoordinate: SIMD2<Float>(1, 1)),
        Vertex(position: SIMD3<Float>(-1, 1, 0), textureCoordinate: SIMD2<Float>(0, 0)),
        Vertex(position: SIMD3<Float>(1, 1, 0), textureCoordinate: SIMD2<Float>(1, 0))
    ]
    
    override init() {
        // ... (이전 코드와 동일)
    }
    
    private func setupTextureCache() {
        // ... (이전 코드와 동일)
    }
}

// MARK: - Views/Components/CameraView.swift
class CameraView: MTKView {
    var renderDelegate: CameraRenderDelegate?
    
    override init(frame frameRect: CGRect, device: MTLDevice?) {
        super.init(frame: frameRect, device: device)
        setupView()
    }
    
    required init(coder: NSCoder) {
        super.init(coder: coder)
        setupView()
    }
    
    private func setupView() {
        self.device = MTLCreateSystemDefaultDevice()
        self.backgroundColor = .black
        self.framebufferOnly = false
    }
}

// MARK: - Views/Components/CameraControls.swift
class CameraControls: UIView {
    var onRecordTap: (() -> Void)?
    var onFilterTap: (() -> Void)?
    
    private lazy var recordButton: UIButton = {
        let button = UIButton(type: .system)
        button.setTitle("녹화", for: .normal)
        button.backgroundColor = .red
        button.layer.cornerRadius = 25
        button.addTarget(self, action: #selector(recordButtonTapped), for: .touchUpInside)
        return button
    }()
    
    private lazy var filterButton: UIButton = {
        let button = UIButton(type: .system)
        button.setTitle("필터 변경", for: .normal)
        button.addTarget(self, action: #selector(filterButtonTapped), for: .touchUpInside)
        return button
    }()
    
    private lazy var timerLabel: UILabel = {
        let label = UILabel()
        label.textColor = .white
        label.font = .systemFont(ofSize: 24, weight: .bold)
        label.text = "10"
        label.textAlignment = .center
        return label
    }()
    
    @objc private func recordButtonTapped() {
        onRecordTap?()
    }
    
    @objc private func filterButtonTapped() {
        onFilterTap?()
    }
    
    // ... Layout 코드
}

// MARK: - ViewControllers/MetalCameraViewController.swift
class MetalCameraViewController: UIViewController {
    private var cameraView: CameraView!
    private var cameraControls: CameraControls!
    private var cameraController: MetalCameraController!
    
    private var currentFilter: FilterType = .normal
    private var recordingTimer: Timer?
    private var remainingTime: Int = 10
    
    override func viewDidLoad() {
        super.viewDidLoad()
        setupViews()
        setupCameraController()
        setupBindings()
    }
    
    private func setupViews() {
        cameraView = CameraView(frame: view.bounds, device: MTLCreateSystemDefaultDevice())
        cameraControls = CameraControls()
        
        view.addSubview(cameraView)
        view.addSubview(cameraControls)
        
        // Layout constraints
    }
    
    private func setupCameraController() {
        cameraController = MetalCameraController()
    }
    
    private func setupBindings() {
        cameraControls.onRecordTap = { [weak self] in
            self?.handleRecordTap()
        }
        
        cameraControls.onFilterTap = { [weak self] in
            self?.handleFilterTap()
        }
    }
    
    private func handleRecordTap() {
        if recordingTimer == nil {
            startRecording()
        } else {
            stopRecording()
        }
    }
    
    private func handleFilterTap() {
        switch currentFilter {
        case .normal: currentFilter = .grayscale
        case .grayscale: currentFilter = .cartoon
        case .cartoon: currentFilter = .normal
        }
        // Update filter in camera controller
    }
    
    // ... Recording and timer related methods
}

// MARK: - Utils/VideoExporter.swift
class VideoExporter {
    static func exportVideo(at url: URL, completion: @escaping (Result<URL, Error>) -> Void) {
        // Video export implementation
    }
}

// MARK: - Protocols/CameraRenderDelegate.swift
protocol CameraRenderDelegate: AnyObject {
    func renderFrame()
    func updateFilter(_ type: FilterType)
}

여기까지...  

직접 코드를 나눠어 넣었을때.... MetalCameraViewController.swift 파일에 먼가 이상함을 감지했다. 

to be continue...

반응형
Posted by onlyTheOne
,
반응형

최근 Claude 를 활용해서 필터 효과가 동영상 제작 앱을 하나 만들어 보았습니다. 

마무리 직압 중인데.... 무언가 남겨야 할 거 같아...

시작글을 올릴려고 합니다. 

이 동영상 촬영 앱은

Metal Framework를 사용한 소스코드이며 녹화와 화면에 실시간으로 보여지도록 되어 있습니다.

Swift 언어 기반에 SwiftUI는 사용하지 않았습니다. 

내일 부터 정리해서 올리도록 하겠습니다. 

반응형
Posted by onlyTheOne
,
반응형

만들고 있는 오디오 믹싱앱이 하나 있습니다. (최근 개인적 스케줄로 홀딩된 상태 입니다. )

여기서 제공하기 위한 BGM 을 가라지밴드로 만들었는데 배포 될 예정의 곡이라 업로드합니다. 

다섯번째 BGM 업로드 합니다. (총 10개 파일 입니다.)

(나머지 파일들은 시간날때 업로드 해두도록 하겠습니다.)

 

05_sample.mp3
1.45MB

반응형
Posted by onlyTheOne
,
반응형

만들고 있는 오디오 믹싱앱이 하나 있습니다. (최근 개인적 스케줄로 홀딩된 상태 입니다. )

여기서 제공하기 위한 BGM 을 가라지밴드로 만들었는데 배포 될 예정의 곡이라 업로드합니다. 

네번째 BGM 업로드 합니다. (총 10개 파일 입니다.)

(나머지 파일들은 시간날때 업로드 해두도록 하겠습니다.)

04_smaple.mp3
2.14MB

반응형
Posted by onlyTheOne
,
반응형

만들고 있는 오디오 믹싱앱이 하나 있습니다. (최근 개인적 스케줄로 홀딩된 상태 입니다. )

여기서 제공하기 위한 BGM 을 가라지밴드로 만들었는데 배포 될 예정의 곡이라 업로드합니다. 

세번째 BGM 업로드 합니다. (총 10개 파일 입니다.)

(나머지 7개 파일은 시간날때 업로드 해두도록 하겠습니다.)

03_sample.mp3
3.27MB

반응형
Posted by onlyTheOne
,
반응형

만들고 있는 오디오 믹싱앱이 하나 있습니다. (최근 개인적 스케줄로 홀딩된 상태 입니다. )

여기서 제공하기 위한 BGM 을 가라지밴드로 만들었는데 배포 될 예정의 곡이라 업로드합니다. 

두번째 BGM 업로드 합니다.

02_sample.mp3
4.36MB

반응형
Posted by onlyTheOne
,
반응형

만들고 있는 오디오 믹싱앱이 하나 있습니다. (최근 개인적 스케줄로 홀딩된 상태 입니다. )

여기서 제공하기 위한 BGM 을 가라지밴드로 만들었는데 배포 될 예정의 곡이라 업로드합니다. 

 

01_sample.mp3
2.18MB

반응형
Posted by onlyTheOne
,
반응형

RxSwift, MVVM... 먼가... 공부하며 정리한 내용을... 적어 보려 한다. 

 

이게 먼가... 봐도 봐도 모르겠는..

< 출처 : pixabay >

 

이제야... 음... 놓친게 무엇인지... 

 

알겠다 ㅎㅎㅎ 

 

근데... 이건 진짜... 시퀀셜 이라고 해야 할까.... 

 

이걸 하고 / 이걸 하고 / 이걸 해야 RxSwift, MVVM이 먼지 감이 오는 상황이 되는 것이다. 

 

 

자! 그럼 윗줄에 내가 쓴 1번 이걸 하고, 2번 이걸 하고, 3번 이걸 해야에 대해서 

 

아주 디테일하게 잘 써주신 분들이 계셔 그분들의 글을 퍼오면 예의가 아니니 

링크를 붙여 두려 한다. 

 

1번 이걸 하고 

https://pilgwon.github.io/blog/2017/10/09/RxSwift-By-Examples-2-Observable-And-The-Bind.html

 

예제로 시작하는 RxSwift #2 – 옵저버블과 바인드

RXSWIFT BY EXAMPLES #2 – OBSERVABLE AND THE BIND.

pilgwon.github.io

 

2번 이걸 하고 

http://blog.naver.com/tmondev/221064638672

 

RxSwift와 RxCocoa로 만드는 iOS 앱

요즘 개발자들 사이에 핫한 키워드 중 하나는 Rx다. Rx는 Reactive Extensions의 약자로 신기술에 관심...

blog.naver.com

3번 이걸 하면 

https://blog.nerdfactory.ai/2019/03/12/rx-swift-service.html

 

너드팩토리

너드팩토리에서 운영하는 블로그 입니다.

blog.nerdfactory.ai

 

 

그리고 나서 아래 예제 소스 코드를 보면!!!! 

https://github.com/yokurin/RxSwift-MVVM-iOS 

 

yokurin/RxSwift-MVVM-iOS

SwiftMVVM is an sample iOS App written in Swift using the MVVM architecture. - yokurin/RxSwift-MVVM-iOS

github.com

 

그래도 이해가 안 갈 수도 있다. 

 

 

RxSwift와 RxCocoa가 각각 무슨일을 하는지, 어떤 개념인지 우선 이해를 하고 

 

그걸 바탕으로 예제를 참고 하면 

 

< 출처 : pixabay > 

계속 반복하고 계속 찾아 보면 마침내 우리는 퍼즐이 맞추게 될 것이다.

 

우리에게 퍼즐을 맞추는 방법을 시간 내어 글 써주신 블로거 분들께 다시한번 감사의 인사를 드리며

 

 

다음엔... MVVM을 하려면 RxSwift가 필수 인가?? 에 대해서 적어 보려 한다. 

 

 

 

 

반응형
Posted by onlyTheOne
,
반응형

최근 다시 RxSwift, MVVM을 공부하고 있다. 

 

그냥 글만 보니 멍.... 

 

멍한 상태가 계속 되기에 

출처 : Pixabay

그래서... 안되겠다 싶어 스터디 목적으로 텀 프로젝트를 진행 하고자 

 

열심히 자료를 찾아서 보기 시작 했다 

 

 

첫번째 본 글 

 

PilGwonKim 님이 영어 원문으로 되어 있는 글을 한국어로 번역해서 올려주신 글

( 뵌적은 없지만 내공이 꽤 있으신 분 같아 보인다. 일단 영어를 잘하시니 그걸로 투 따봉!  )

https://pilgwon.github.io/blog/2018/10/09/Creating-an-iOS-app-with-MVVM-and-RxSwift-in-Minutes.html 

 

RxSwift와 MVVM으로 iOS앱 만들기

Creating an IOS app with MVVM and RxSwift in minutes

pilgwon.github.io

 

따라 해보는데... 으잉?.... 내가 공부를 덜했나 싶어... 하다 중간에 막혔다.

 

게다가 RxSwift만 있어야 하는게 아니라 RxCocoa도 필요 하더라 (이건 머야...) 

 

그래서 다시 구글링.. 

 

아 이걸 봐야 겠구나 하게 되서 찾은 링크 

 

http://minsone.github.io/programming/reactive-swift-observable-vs-driver

 

[ReactiveX][RxSwift]Observable과 Driver

Driver RxSwift는 다른 언어의 Rx 구현체와는 다르게 Driver라는 unit을 제공합니다. 하지만 기본으로 Observable을 제공하기 때문에 Driver를 언제 써야 할 지 궁금했습니다. Driver는 UI layer에서 좀 더 직관적으로 사용하도록 제공하는 unit입니다. Observable는 상황에 따라 MainScheduler와 BackgroundScheduler를 지정해줘야 하지만 Driver는 MainScheduler에서 사용합니

minsone.github.io

민소네 님 블로그 포스트 이다. 무려 2016년도 글.... 나는 2016년도에 머했나... (

OTL... 아마 스타트업 창업 준비하느라 정신 없던 시절인듯... )

 

보고서 아하! 인지 했다. 

 

그리고 다시 저기 위에 필권님이 번역해 주신 걸 따라 하다... 결국 깃허브 가서 플젝 다운 받았다. 

https://github.com/NavdeepSinghh/MVVM_RxSwift_Starter

 

NavdeepSinghh/MVVM_RxSwift_Starter

Starter project for MVVM and RxSwift IOS project. - NavdeepSinghh/MVVM_RxSwift_Starter

github.com

 

이게 아니잖아 (쿨럭... ) 

 

 

그래서 다시 따라 할만한걸 찾아 본 글 

1번. 

https://mrgamza.tistory.com/502?category=574448 

 

RxSwift 시작하기

제가 Reactive를 알게 된게 1년정도 된것 같네요. 그렇게 알게 되고 이것저것 하다보니 이것에 대한 매력을 좀 느끼고 있는 편입니다. 그 당시에 MVVM 패턴으로 개발을 시작하였고 현재 진행하는 프로젝트도 이것..

mrgamza.tistory.com

역시 실패 ㅜㅜ 

 

2번. 

https://myseong.tistory.com/9 

 

RxSwift 시작하기 (설치 & Button Tap Event - DisposeBag, rx.Tap )

RxSwift 시작하기RxSwift 시작하기 (설치 & Button Tap Event) RxSwift설치부터 tap event를 bind와 subcribe를 이용하여 이벤트를 바인딩 하는 것을 포스팅 할것 이다. 이전에는 RxSwift의 간략적인 내용을 포스..

myseong.tistory.com

또 실패 ㅜㅜ 

 

코딩에 소질이 없나? 싶을 정도의 ㅜㅜ 

 

그러다 다시 이글을 보고 

3. 

https://eunjin3786.tistory.com/29?category=706836

 

[RxSwift] Rx로 TableView를 그리는 4가지 방법 + setDelegate

이렇게 준비를 한다..! 1. 뷰컨에 TableView를 올려주고 2. Tableview에 TableViewCell을 올려주고 3. TableViewCell의 identifier를 NameCell 로 설정해준다 그리고 RxTableViewController에 RxSwift와 RxCocoa..

eunjin3786.tistory.com

아 먼가 어렵다. 라는 느낌이 들었다.. 역시 실패 

 

내가 너무 기술 습득해 안일함이 있었구나 느끼며 ㅜㅜ 

 

( 1,2,3번 같은 좋은 글을 써주신 분들께 죄송스러운데 제가 내공이 부족해서 그런지 어려워서 못따라 가겠네요 ㅜㅜ )

 

출처 : Pixabay

( 그리고 마음속 한 구석에선 ... 몰라 배째~! 라는 마음도 있었다.. )

 

 

그래 이론을 다시 이해해 보자 하며 

 

이 글을 보게 되고 

https://brunch.co.kr/@tilltue/37

 

iOS 아키텍쳐 바라보기

MVC, MVVM, FLUX, ReSwift, ReactorKit | 이 글은 각각의 아키텍쳐를 설명하는 글은 아니다. 아키텍쳐를 알아보고 관련되어 파생된 framework 사용을 고민하는 과정에서 정리한 내용을 기록하기 위해 작성한 글이다. 지극히 개인적인 의견들이 포함되어있다. 글 내용을 제외하고 아래 링크된 여러 글들만 모아 봐도 도움이 될것이라 생각된다. 1. 좋은 앱을 만들기 위해서는 어떤 아키텍쳐가 필요할까?

brunch.co.kr

 

그리고 이 글도 보게 되었다

https://brunch.co.kr/@tilltue/10

 

RxSwift, Filtering Observable

Debounce, Distinct, Filter, Take, Skip등 | * 이 포스트는 RxSwift 4.3.1, swift 4.2 버전을 기준으로 작성되었습니다. 이벤트들을 특정 조건이 맞을때 발생하도록 이벤트를 필터링 하는 메서드들에 대해 알아보자 1. Debounce http://rxmarbles.com/#debounce 지정한 시간간격 내에 마지막 하나의 이벤트만 전달한다. 아래 그림처럼 이벤트 간격이 설정(debou

brunch.co.kr

보고 나서 느낀건... 먼가... 싶은 느낌이........ 

 

도통 이해가 안간다. 

 

그래서 흔히 많이 가는 사이트 ( 난 여기 정기구독 중인데 동영상을 이제서야 제대로 본다... ) 

 

https://www.raywenderlich.com/4743-beginning-rxswift/lessons/5

 

Subscribing to Observables: Part 1

 

Learn how to subscribe to an observable, and how to manage memory by using dispose bags.

 

www.raywenderlich.com

 

여기도 초기 예제가 구성이 안되서 결국 여기서 제공해주는 샘플 받아서 

 

거기에 덮어 쓰며 진행 하고 있다. 

 

 

자 그럼 멀 해보고 싶은 것인가... 

 

API 데이터를 내려 받는걸 기존 alamofire를 통해 api 하니씩 찌르고 응답받고 하는 과정을 

 

새로운? RxSwift 에 MVVM 기법을 써보고 싶었다. 

 

일단 raywenderlich 를 참고해서 따라가 보고 

 

이론 자료좀 더 봐야 할 것 같다. 

 

추가로 필권님?이 알려주신 github 관련 api 접근을 위해 github api 페이지 링크를 적어둔다.

https://developer.github.com/v3/repos/#list-all-topics-for-a-repository

 

Repositories

Get started with one of our guides, or jump straight into the API documentation.

developer.github.com

 

RxSwift, MVVM, RxCocoa 이런것에 대한 개념 이해를 하고 #2 글을 적도록 하겠다. 

 

 

반응형
Posted by onlyTheOne
,