[디아블로2 레저렉션] 2-3일차 – PC용도 사버렸다

어제 닌텐도로 즐겁게 하고, 오늘도 하고 싶은데 아들놈이 닌텐도를 놓지 않는다.. 한참을 기다리다가 할 수 없이 PC판용 디아블로2 레저렉션을 또 구매해버렸다.
한시간쯤 즐겁게 8인 파티로 즐겁게 렙업을 하고 있었는데, 링크를 깨달라며 나만의 시간을 뺏어갔다.
지금은 옆에서 링크를 봐주며, 소서리스 육성계획을 준비중이다. ㅋㅋㅋ

블리자드 소서리스 스킬트리 계획

콜드

라이트닝

파이어

찍고 싶은것들을 모두 참아내고 이렇게 찍어나가는거야.
후후후…

3일차 계획 (일단 뭐라도 주서입자)

아카라에게 쓸만한 스태프를 산다
2 소켓 뚜껑을 하나 산다
최하급 사파이어 2개 뚜껑에 박아 쓰자

현재 타워까지 진행이 되었으니 본격적인 노가다의 시작이다…

스텔스 (Tal+Eth, 17레벨 갑옷)를 목표로 룬 노가다

  • 탈 1개 에드 1개 (필수)
  • 티르 3개 (꽃잎, 천저, 통찰력)
  • 네프 2개 (천저, 연기)
  • 에드 2개 (스텔스, 제왕운시)
  • 아이드 1개 (캐스터 크래프트 벨트)
  • 탈 & 랄 4개 이상 (꽃잎, 스피릿, 통찰력, 스텔스, 큐빙 등)

스텔스 준비물을 모으면서 같이 할 일

레지(5% 이상) 참, 패캐 아뮬 / 링 확보
룬위드용 2소켓 뚜껑, 2소켓 갑옷 창고에 진열 (Act1 찰시가 팜)

목표는 5일차 안으로 룬을 졸업하고 싶다…

[디아블로2 레저렉션] 구매

Diablo2 Resurrected 닌텐도용 구입 후기

토요일부터 구매를 망설이다가 닌텐도 스위치에서 결제를 진행했다.
망할.. 아들놈 계정에다가 5만원을 충전해버려서, 5천원을 더 충전하고 구매할까..
아니면 다시 5만원을 충전할까 고민하다가..
18세 이상이어야 한다는 구매조건 때문에..
다시 5만원을 충전해버리는 사태가 발생했다.

눈물을 머금고 다시 결제했다. 추후에 패밀리 사용권 결제에 사용하기로 기약하면서…

인트로 이미지

게임 체험기

악마때문에 잠을 못잔 수도승의 시네마틱.. 끝내주고..
처음 진행할때는 약간 잘못산건가라는 생각이 들었지만, 진행할수록 찐잼이라고 느껴졌다.

첫번째 퀘스트 완료
역시 RPG는 이런 기분때문에 하는거 아니였냐! 국산 게임업계는 각성해라!
인트로 이미지

약 2시간의 게임후 내 레벨...
2시간 후

게임을 2시간 진행해본 소감

단점

조각감이 별루다. (익숙해지면서 괜찮아지기 시작했다.)
대화를 할수 없다는게 그렇다.
(어떤 사람들은 팔로우 미 같은 액션을 하던데 아직 할줄 모른다.)
마우스로 휙휙 가지 못하는것이 아쉽다.

장점

시네마틱이 웅장해서 좋았다.
옛날 감성이 돋고 몰입감이 좋았다.
처음의 별루였던 조작감이 익숙해지면서 잼있어 지기 시작했다.
템 구경하는 맛이 있다.

[ReactJS] 학습해보자.

Create React App으로 테스트

노마더코딩 리액트 기초배우기
ReactJS를 보다가 여기까지 흘러들어왔다.

Create React App
흘러 들어온김에 좋은 기술하나 배워가보자. 쿨럭.
설치법은 간단하다

npx create-react-app my-app
cd my-app
npm start

이렇게 하면, 로컬페이지가 로드된다.

my-app내 App.js를 살펴보자

JSX는 리액트 컴포넌트를 만들때 사용되는 언어
아래와 같은 코드가 JSX라고 한다.

    <div className="App">
      <header className="App-header">
        <img src={logo} className="App-logo" alt="logo" />
        <p>
          Edit <code>src/App.js</code> and save to reload.
        </p>
        <a
          className="App-link"
          href="https://reactjs.org"
          target="_blank"
          rel="noopener noreferrer"
        >
          Learn React
        </a>
      </header>
    </div>

마치며

현재 위치: 리액트 기초 배우기 #5 ReactJS로 웹 서비스 만들기
내가 뭘하려다가 ReactJS까지 흘러왔는지 순간 까먹었다. 내가 하고 싶은건.. 아마존 NoSQL 사용이였는데 말이다... 쿨럭.
뭐 하는김에 제대로 하면 좋지. 취미생활코딩이니까...

오늘은 여기까지.

[Tips] Visual Studio Code Cmd로 실행하는 법

Visual Studio Code Cmd로 실행하는 법

  1. 비주얼 스튜디오 코드를 일단 실행 시킨다.
  2. Command Palette (⇧⌘P)를 실행한다.
  3. Shell command를 입력하면, Shell Command: Install ‘code’ command in PATH command가 노출된다.
  4. 노출 부분을 클릭한다.
    해당이미지
  5. 이제 커맨드창에서 code를 입력하면 비주얼스튜디오 코드가 실행된다.

[iOS] SceneDelegate에 대한 학습

SceneDelegate

AppDelegate & SceneDelegate

  • AppDelegate

iOS 13 미만

Process LifeCycle UI LifeCycle
App Launched Entered Foreground
App Terminate Became Active
... ...

iOS 13이상

AppDelegate SceneDelegate
Process LifeCycle UI LifeCycle
Scene LifeCycle Entered Foreground
Session Created Became Active
Session Discarded

iOS12까지는 하나의 앱은 하나의 window로 구성되어 있었다.
iOS13부터는 window의 개념이 scene으로 변경되었으며, 하나의 앱은 여러개의 scene을 가질수 있게 되었다.
다시 말해 하나의 앱에서 여러개의 scene을 보여줄수 있게 되었다.

SceneDelegate

AppDelegate의 역할 중 UI의 상태를 알 수 있는 UILifeCycle에 대한 부분을 SceneDelegate가 하게 되었다.

SceneDelegate의 생명주기

  1. [SceneDelegate] scene(_:, willConnectTo:, options:)

    func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
    // Use this method to optionally configure and attach the UIWindow `window` to the provided UIWindowScene `scene`.
    // If using a storyboard, the `window` property will automatically be initialized and attached to the scene.
    // This delegate does not imply the connecting scene or session are new (see `application:configurationForConnectingSceneSession` instead).
    guard let _ = (scene as? UIWindowScene) else { return }
    }

    scene이 앱에 추가될 때 호출. 단 여기서 ViewController와 같은 클래스 객체를 만들어 사용할 때, 아직 viewDidLoad()가 호출되지 않음

  2. sceneDidDisconnect(_ 🙂

    func sceneDidDisconnect(_ scene: UIScene) {
    // Called as the scene is being released by the system.
    // This occurs shortly after the scene enters the background, or when its session is discarded.
    // Release any resources associated with this scene that can be re-created the next time the scene connects.
    // The scene may re-connect later, as its session was not necessarily discarded (see `application:didDiscardSceneSessions` instead).
    }

    scene의 연결이 해제될 때 호출

  3. sceneDidBecomeActive(_: )

    func sceneDidBecomeActive(_ scene: UIScene) {
    // Called when the scene has moved from an inactive state to an active state.
    // Use this method to restart any tasks that were paused (or not yet started) when the scene was inactive.
    }

    app switcher에서 선택되는 등 scene과의 상호작용이 시작될 때 호출

    • app switcher : 홈버튼을 두번누르거나 아이폰 하단에서 위로 스와이프 했을 때 현재 실행중인 앱들이 보이는 화면
  4. sceneWillResignActive(_:)

    func sceneWillResignActive(_ scene: UIScene) {
    // Called when the scene will move from an active state to an inactive state.
    // This may occur due to temporary interruptions (ex. an incoming phone call).
    print("[SceneDelegate] sceneWillResignActive(_ scene: UIScene)")
    }

    사용자가 scene과의 상호작용을 중지할 때 호출(다른 화면으로의 전환과 같은 경우)

  5. sceneWillEnterForeground(_:)

    func sceneWillEnterForeground(_ scene: UIScene) {
    // Called as the scene transitions from the background to the foreground.
    // Use this method to undo the changes made on entering the background.
    print("[SceneDelegate] sceneWillEnterForeground(_ scene: UIScene)")
    }

    scene이 foreground로 진입할 때 호출

  6. sceneDidEnterBackground(_:)

    func sceneDidEnterBackground(_ scene: UIScene) {
    // Called as the scene transitions from the foreground to the background.
    // Use this method to save data, release shared resources, and store enough scene-specific state information
    // to restore the scene back to its current state.
    print("[SceneDelegate] sceneDidEnterBackground(_ scene: UIScene)")
    }

    scene이 background로 진입할 때 호출

AppDelegate 생명주기

AppDelegate - Scene LifeCycle

AppDelegate에는 Session LifeCycle에 대한 역할이 추가되었다.
SceneSession은 앱에서 생성한 모든 scene의 정보를 관리한다.

// MARK: UISceneSession Lifecycle
func application(_ application: UIApplication, configurationForConnecting connectingSceneSession: UISceneSession, options: UIScene.ConnectionOptions) -> UISceneConfiguration {
    // Called when a new scene session is being created.
    // Use this method to select a configuration to create the new scene with.
    return UISceneConfiguration(name: "Default Configuration", sessionRole: connectingSceneSession.role)
}

func application(_ application: UIApplication, didDiscardSceneSessions sceneSessions: Set<UISceneSession>) {
    // Called when the user discards a scene session.
    // If any sessions were discarded while the application was not running, this will be called shortly after application:didFinishLaunchingWithOptions.
    // Use this method to release any resources that were specific to the discarded scenes, as they will not return.
}

Scene?

UIKit은 UIWindowScene 객체를 사용하는 앱 UI의 각 인스턴스를 관리한다. Scene에는 UI의 하나의 인스턴스를 나타내는 windows와 view controllers가 들어있다. 또한, 각 scene에 해당하는 UIWindowSceneDelegate 객체를 가지고 있고, 이 객체는 UIKit과 앱 간의 상호작용을 조정하는데 사용된다.
Scene들은 같은 메모리와 앱 프로세스 공간을 공유하면서 서로 동시에 실행된다. 결과적으로 하나의 앱은 여러 Scene과 Scene delegate 객체를 동시에 활성화 할 수 있다.
(Scenes - Apple Development Document)

Scene Session?

UISceneSession 객체는 Scene의 고유의 런타임 인스턴스를 관리한다. 사용자가 앱에 새로운 Scene을 추가하거나 요청하면, 시스템은 그 Scene을 추적하는 session 객체를 생성한다. 그 Session에는 고유한 식별자와 scene의 구성 세부사항(configuration details)가 들어있다.
UIKit은 session 정보를 그 Scene 자체의 생명주기동안 유지하고 app switcher에서 사용자가 그 Scene을 클로징하는 것에 대응하여 그 session을 파괴한다.
session 객체는 직접 생성하지 않고 UIKit이 앱의 사용자 인터페이스에 대응하여 생성한다.
또한, 아래 함수를 통해서 UIKit에 새로운 Scene과 Session을 프로그래밍적 방식으로 생성할 수 있다.
(UISceneSession - Apple Development Document)

func application(_ application: UIApplication, configurationForConnecting connectingSceneSession: UISceneSession, options: UIScene.ConnectionOptions) -> UISceneConfiguration 
func application(_ application: UIApplication, didDiscardSceneSessions sceneSessions: Set<UISceneSession>)

iOS13부터 AppDelegate의 역할

  1. 앱의 데이터 구조를 초기화 하는 것
  2. 앱의 Scenes의 환경설정(Configuration)
  3. 앱 밖에서발생한 알림(베터리 부족, 다운로드 완료 등)에 대응
  4. 특정한 Scenes, views, view controllers에 한정되지 않고 앱 자체를 타겟하는 이벤트에 대응하는 것
  5. 애플 푸쉬 알림 서브스와 같이 실행시 요구되는 모든 서비스를 등록
    (UIApplicationDelegate - Apple Development Document)

Deployment Target이 iOS 13 미만인 상황에서는?

iOS12이하는 단일 window 환경임으로, 아래와 같이 Scene처리를 제거할 수 있다.

  1. SceneDelegate.swift 제거
  2. AppDelegate에서 UISceneSession 관련 두개의 메소드 제거
  3. SceneDelegate로 옮겨진 window 프로퍼티를 AppDelegate로 옮기기
    var window: UIWindow?
  4. info.plist에서 Scene과 관련된 Manifest인 Application Scene Manifest 삭제

GRDB를 사용하다가 생긴 문제점 공유

GRDB를 사용하다보니 JOIN시에 해당 구조체를 가져오는게 쉽지 않다는 문제점을 발견했다.
이를 해결하기 위해, 검색을 하다보니 GRDB를 더 깊게 이해해야 한다는 문제점에 도달했다.

Sqlite3으로 모든 작업을 돌리기로 결정.
이유는 Sqlite3은 내가 맘대로 만들고, 제어도 더 쉽다고 생각했다.
Join과 cascade등의 처리를 위해서는 Sqlite3을 직접 사용하는게 더 좋은것 같다.

일단, Sqltie3으로 개발을 완료하고 나서 추후 nosql을 사용해보겠다.

오랫만에 개인 프로젝트를 하나 해보고 있는데, 트랜드를 다시 익히려다 보니 온갖 삽질을 다 하고 있다..

GRDB를 사용해서 대부분의 것들도 사용이 가능한거 같긴한데, 사전 지식이 꽤 많이 필요한거 같다.

RxSwift 쉽지 않구나.

Swift를 지나고 Reactive를 지나서 가는 여정이 참으로 험난하다.
뭔가 깨달은것 같으면 다시 막힘에 들어서는 반복중이다.

간단한걸 RxSwift MVVM으로 만드는게 이렇게 고통스러울줄이야...
좀 자료를 정리해서 글을 남겨야 할것 같다.

어떻게 글을 정리하고 글을 써야 할지 고민을 좀 해봐야 겠다.
정리가 안된다.. ㅠ

Sqlite3 JOIN

앱 개발자는 DB를 사용할 일이 그렇게 많지 않다.
이참에 대강 알고 있던 JOIN을 정리하려고 한다.

SQLite3는 세 가지 조인 방식을 지원하고 있는데, INNER JOIN, LEFT JOIN, CROSS JOIN 이 있다.
문법은 다음과 같다.

SELECT {col1, alias1.col2...} FROM {tab1} AS {alias1}
{INNER/LEFT/CROSS} JOIN {tab2} as {alias2} ON {결합조건}
-- ON 대신 USING을 쓸 수 있다.
{INNER/LEFT/CROSS} JOIN USING {결합칼럼}

JOIN 샘플코드

select * from TB_BK_ST as BS join TB_BK as BK ON BK.id = BS.id ;
select * from TB_BK_ST as BS INNER JOIN TB_BK as BK ON BK.id = BS.id;
select * from TB_BK_ST as BS LEFT JOIN TB_BK as BK ON BK.id = BS.id;
select * from TB_BK_ST as BS CROSS JOIN TB_BK as BK ON BK.id = BS.id;
select * from TB_BK_ST as BS INNER JOIN TB_BK as BK ON BK.id = BS.id INNER JOIN TB_BK_MM AS MM ON BS.id = MM.id;
select * from TB_BK_ST as BS INNER JOIN TB_BK as BK ON BK.id = BS.id LEFT JOIN TB_BK_MM AS MM ON BS.id = MM.id;
select * from TB_BK_ST as BS INNER JOIN TB_BK as BK ON BK.id = BS.id CROSS JOIN TB_BK_MM AS MM ON BS.id = MM.id;

INNER JOIN

가장 많이 사용되는 JOIN
조건에 맞는 행이 없는 경우는 모두 제욍시킨다.
교집합과 같다. 해당 값이 없는 테이블이 있다면, 이런 데이터들은 결과에서 제외된다.

LEFT JOIN

왼쪽 테이블을 기준으로 알수 없는 값들을 NULL로 채워서 만든다.

CROSS JOIN

양쪽 테이블로 JOIN을 실행한다.
용도는 아직 잘 모르겠다.

RxTableView

RxSwift를 학습은 했는데, 쓸 때마다 기억이 안난다.
아직 익숙해지지 않아서일까.. 그래서 정리해본다.

어떻게 정리해봐야 할까 고민을 해보아야 할것 같다.
일단 방식만 나열하는 걸로...

총 네가지 방식의 사용법이 존재한다.

1. tableView.rx.items 사용하기

    func bindingTableViewItems01() {
        let cities = ["01", "L", "K"]
        let citiesOb: Observable<[String]> = Observable.of(cities)
        citiesOb.bind(to: tableView.rx.items) { (tableView: UITableView, index: Int, element: String) -> UITableViewCell in
            guard let cell = tableView.dequeueReusableCell(withIdentifier: TitleCell.identifier) as? TitleCell else {
                return UITableViewCell()
            }
            cell.title?.text = element
            
            // CellType 변경
            // element 타입을 기준으로 셀을 리턴 가능

            return cell
        }
        .disposed(by: disposeBag)
    }

2. tableView.rx.items(cellIdentifier:String) 사용하기


    func bindingTableViewItems02() {
        let cities = ["02", "L", "K"]
        let citiesOb: Observable<[String]> = Observable.of(cities)
        citiesOb.bind(to: tableView.rx.items(cellIdentifier: TitleCell.identifier))
        { (index: Int, element: String, cell: UITableViewCell) in
            if let cell = cell as? TitleCell  {
                cell.title.text = element
            }
        }
        .disposed(by: disposeBag)
    }
   

3. tableView.rx.items(cellIdendifier:String,cellType:Cell.Type) 사용하기


    func bindingTableViewItems03() {
        let cities = ["03", "L", "K"]
        let citiesOb: Observable<[String]> = Observable.of(cities)
        citiesOb.bind(to: tableView.rx.items(cellIdentifier: TitleCell.identifier, cellType: TitleCell.self))
        { (index: Int, element: String, cell: TitleCell) in
            cell.title.text = element
            cell.textLabel?.text = element + "     " + element
        }
        .disposed(by: disposeBag)
    }

4. tableView.rx.items(dataSource:protocol<RxTableViewDataSourceType, UITabelViewDataSource>) 사용하기


    // tableView를 어떻게 표현할지 미리 지정한 datasource를 사용한 방법
    // pod으로 RxDataSource를 설치
    // TODO: 참고 자료 https://github.com/RxSwiftCommunity/RxDataSources
    func bindingTableViewItems04() {
        // RxDataSource에서는 SectionModelType을 따르는 SectionModel을 이미 구현해 놓았는데, 이것을 사용하면 된다.
        typealias CitySectionModel = SectionModel<String, String>
        typealias CityDataSource = RxTableViewSectionedReloadDataSource<CitySectionModel>
        
        let cities = ["03", "L", "K", "L", "K", "L", "K", "L", "K", "L", "K"]
        let sections = [
            CitySectionModel(model: "first section", items: cities),
            CitySectionModel(model: "second section", items: cities)
        ]
        
        let configureCell: (TableViewSectionedDataSource<CitySectionModel>, UITableView, IndexPath, String) -> UITableViewCell = {
            (datasource, tableView, indexPath, element) in
            guard let cell = tableView.dequeueReusableCell(withIdentifier: TitleCell.identifier, for: indexPath) as? TitleCell else {
                return UITableViewCell()
            }
            cell.title.text = element
            return cell
        }
        let datasource = CityDataSource.init(configureCell: configureCell)

        datasource.titleForHeaderInSection = { datasource, index in
            return datasource.sectionModels[index].model
        }
                
        Observable.just(sections)
            .bind(to: tableView.rx.items(dataSource: datasource))
            .disposed(by: disposeBag)
    }

[21.05.27] 경제적 자유를 향한 일기

금리인상 이슈가 끊이질 않는다.
최근에 코인 이슈도 끊이질 않아서 한 이주동안 사또 스트리머의 코인방송을 봤는데, 무섭더라..
내가 감내할수 있는 투자 종목이 아닌것 같아 들어가지도 못했다.

세상을 살아가기가 점점 더 힘들어 보이는건 나 뿐일까...