<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>jiny_k.log</title>
        <link>https://velog.io/</link>
        <description>iOS developer</description>
        <lastBuildDate>Mon, 24 Jun 2024 03:01:02 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <image>
            <title>jiny_k.log</title>
            <url>https://velog.velcdn.com/images/jiny_k/profile/253a162e-2998-43a1-bc7e-2e38a912ce0b/image.png</url>
            <link>https://velog.io/</link>
        </image>
        <copyright>Copyright (C) 2019. jiny_k.log. All rights reserved.</copyright>
        <atom:link href="https://v2.velog.io/rss/jiny_k" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[Git flow 적용 및 사용]]></title>
            <link>https://velog.io/@jiny_k/Git-flow-%EC%A0%81%EC%9A%A9-%EB%B0%8F-%EC%82%AC%EC%9A%A9</link>
            <guid>https://velog.io/@jiny_k/Git-flow-%EC%A0%81%EC%9A%A9-%EB%B0%8F-%EC%82%AC%EC%9A%A9</guid>
            <pubDate>Mon, 24 Jun 2024 03:01:02 GMT</pubDate>
            <description><![CDATA[<h2 id="git-flow란">Git Flow란?</h2>
<p>브랜치를 나누는 방법에 대한 분류 중 하나입니다.</p>
<p>Git Flow의 특징은 브랜치를 5종류로 나뉩니다.</p>
<p>main(master): 서비스을 직접 배포하는 역할을 하는 브랜치.
feature(기능): 각 기능 별 개발 브랜치. develop을 베이스로 develop에 머지한다.
develop(개발): 다음 버전을 위해 준비하는 브랜치.
release(배포): 배포를 하기 전 내용을 QA(품질 검사)하기 위한 브랜치. develop에서 해당 브랜치를 생성하며, 버그가 있을 경우에는 release 브랜치에서 버그를 픽스. 예) release/1.1.0
hotfix(버그 수정): main 브랜치로 배포를 하고 나서 버그가 생겼을 때 고치기 위한 브랜치입니다.<img src="https://velog.velcdn.com/images/jiny_k/post/d8d73d8f-86b7-4ca2-ae7b-de3ab865fb29/image.png" alt=""></p>
<p><img src="https://velog.velcdn.com/images/jiny_k/post/c72086f4-f28c-4f47-ad99-96e65ef81645/image.png" alt=""></p>
<h2 id="git-flow-적용하기">Git Flow 적용하기</h2>
<p>만약 homebrew가 설치되어있지 않다면, homebrew를 먼저 설치해준 후에 진행해주세요.</p>
<pre><code>$ brew install git-flow-avh

$ git flow version</code></pre><p><img src="https://velog.velcdn.com/images/jiny_k/post/8d0e0214-7fcc-47f2-babf-72566443bf2e/image.png" alt="">
<img src="https://velog.velcdn.com/images/jiny_k/post/94f84454-3bfa-47bc-8ef7-b9e615d17398/image.png" alt=""></p>
<pre><code>git flow init

# 모두 기본 값으로 git flow 세팅
git flow init -d</code></pre><p><img src="https://velog.velcdn.com/images/jiny_k/post/2f4d7f20-4d4b-438d-a678-62f0b370c4bc/image.png" alt=""></p>
<p><img src="https://velog.velcdn.com/images/jiny_k/post/644c8592-9668-4cc4-a10f-dd6672fbcc36/image.png" alt=""></p>
<p><img src="blob:https://velog.io/6662e547-0c9d-4e20-8cff-44a45ec02473" alt="업로드중.."></p>
<p><img src="blob:https://velog.io/4331e5ea-c04e-499b-8434-7c9eb2183758" alt="업로드중.."></p>
<p><img src="blob:https://velog.io/c3b97b93-1897-4ecb-9893-a5ae6b2c2e5b" alt="업로드중.."></p>
<p><img src="blob:https://velog.io/0f27a2fa-f7ea-487b-93ed-8e20fddea291" alt="업로드중.."></p>
<p>git init중 에러가 발생하면 현재 로컬에 변경된 내용이 있거나 ( 미리 커밋해야함 ) master, develop 브랜치가 현재 존재하지않기 때문이다.
master develop브랜치를 미리 만들어놓는다면 init할때 엔터만으로 init 이 가능하다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[SwiftUI Swipe로 삭제버튼 만들기]]></title>
            <link>https://velog.io/@jiny_k/SwiftUI-Swipe%EB%A1%9C-%EC%82%AD%EC%A0%9C%EB%B2%84%ED%8A%BC-%EB%A7%8C%EB%93%A4%EA%B8%B0</link>
            <guid>https://velog.io/@jiny_k/SwiftUI-Swipe%EB%A1%9C-%EC%82%AD%EC%A0%9C%EB%B2%84%ED%8A%BC-%EB%A7%8C%EB%93%A4%EA%B8%B0</guid>
            <pubDate>Thu, 23 Nov 2023 13:08:51 GMT</pubDate>
            <description><![CDATA[<p>카카오톡 채팅방 처럼 스와이프해서 삭제버튼을 숨기는 기능
SwiftUI에는 기본으로 제공한다!</p>
<p><img src="https://velog.velcdn.com/images/jiny_k/post/3cbe930a-49e8-461d-8cb2-38ab976a8615/image.png" alt=""></p>
<p>최근에 SwiftUI로 만든 내 작고 소중한 TODOList 앱 <strong>YamTODO</strong>
태스크를 삭제할때 스와이프 하면 저렇게 삭제 버튼이 나타나는 기능은 List의 SwipeActions다.</p>
<p>SwipeActions는 </p>
<pre><code>func swipeActions&lt;T&gt;( edge: HorizontalEdge = .trailing, allowsFullSwipe: Bool = true, content: () -&gt; T ) -&gt; some View where T : View</code></pre><p>요로코롬 생겼는데 
leading trailing 좌우로 스와이프 할 수 있고 
fullSwipe로 완전 밀어서 날려버릴수 있다. 
content에는 동작을 작성하면 됀다.</p>
<pre><code>.swipeActions(edge: .leading, allowsFullSwipe: false) {
     Button { 
        isShowDeleteAlert.toggle()
     } label: {
         Label(&quot;Delete&quot;, systemImage: &quot;trash.circle&quot;)
     }
         .tint(.red)
 }</code></pre><p>앱 동작은 이런식으로 사용했다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Swift의 새로운 로컬라이즈 Localizable.catalog 를 적용해보자.]]></title>
            <link>https://velog.io/@jiny_k/Swift%EC%9D%98-%EC%83%88%EB%A1%9C%EC%9A%B4-%EB%A1%9C%EC%BB%AC%EB%9D%BC%EC%9D%B4%EC%A6%88-Localizable.catalog-%EB%A5%BC-%EC%A0%81%EC%9A%A9%ED%95%B4%EB%B3%B4%EC%9E%90</link>
            <guid>https://velog.io/@jiny_k/Swift%EC%9D%98-%EC%83%88%EB%A1%9C%EC%9A%B4-%EB%A1%9C%EC%BB%AC%EB%9D%BC%EC%9D%B4%EC%A6%88-Localizable.catalog-%EB%A5%BC-%EC%A0%81%EC%9A%A9%ED%95%B4%EB%B3%B4%EC%9E%90</guid>
            <pubDate>Tue, 21 Nov 2023 01:56:39 GMT</pubDate>
            <description><![CDATA[<h3 id="기존의-로컬라이즈">기존의 로컬라이즈</h3>
<p>그동안 많은 프로젝트에서 Localizable.string 을 봐왔다. 
많은 사이트들에서 string파일을 편리하게 관리하고 안드로이드와 동일하게 관리할 수 있도록 지원한다.</p>
<p>새로운 앱 출시를 앞두고 로컬라이즈를 등록하려고 했다. </p>
<p><img src="https://velog.velcdn.com/images/jiny_k/post/1856d54d-a3ae-44d7-9504-5c1635d6fa06/image.png" alt=""></p>
<p>내가알던 Strings file은 이미 레거시가 되어버렸던것.. ㅠㅠ
새로 로컬라이즈를 생성한지 오래되서 언제부터 레거시가 되었는지도 모르겠다. </p>
<p>아무튼 catalog를 사용해보자! </p>
<h3 id="catalog-file-추가">Catalog file 추가</h3>
<p>파일을 추가해서 catalog 파일을 추가한다. 
<img src="https://velog.velcdn.com/images/jiny_k/post/df71740c-e130-49ae-9a75-3814f34f83e1/image.png" alt=""></p>
<h4 id="기본-언어-설정">기본 언어 설정</h4>
<p>기본값은 영어로 되어있다. 
이 부분은 프로젝트 설정이 기본 영어로 되어있기 때문인데 
<img src="https://velog.velcdn.com/images/jiny_k/post/d51119f8-5559-4797-b013-3c35d334ce2e/image.png" alt=""></p>
<p>프로젝트 설정의 Info에서 Localizations 부분의 Default를 변경하면 변경된다. </p>
<h3 id="값-추가">값 추가</h3>
<p>키 벨류 형태로 되어있는데 +를 눌러서 키값을 추가할 수 있다. 
다만 이미 프로젝트가 어느정도 진행되었다면 그냥 파일만 만든채로 빌드를 하면 알아서 키값을 생성해준다. 
<img src="https://velog.velcdn.com/images/jiny_k/post/3d0e3d1a-a181-4ae0-a6ae-43f8dc0a2a64/image.png" alt=""></p>
<p>혼돈의 도가니 ㅋㅋㅋㅋㅋ
자동으로 생성된 키값은 키값자체를 수정할수 없고 프로젝트에서 해당 텍스트를 찾아서 쓸 키값으로 변경해주고 다시 빌드하면 자동으로 적용된다.</p>
<p>예를들면 사진의 마이페이지 의 Text를 찾아서 
<img src="https://velog.velcdn.com/images/jiny_k/post/17c02694-f6ce-46bf-8695-c796fd8af201/image.png" alt="">
My Page로 변경해줬더니 키값이 My Page가 되었다. </p>
<p>별도로 키값을 생성하지 않아도 된다는 점에 귀찮음을 덜었다. 
이름짓는게 생각보다 시간이 오래드니까... </p>
<h3 id="관리">관리</h3>
<p>기존처럼 String Class 생성해서 따로 스트링만 관리해줘도 되지만 catalog는 값을 알아서 찾아서 키로 등록해 주기때문에 값이 중복되지 않는다.
따라서 별도의 String파일로 관리할 필요가 없다. </p>
<p>물론 하드코딩마냥 &quot;확인&quot; 이런 텍스트가 보기 싫은 사람들은 여전히 String파일로 관리하겠지만,,<img src="https://velog.velcdn.com/images/jiny_k/post/507155a8-1a07-41c0-b415-73521b060ef3/image.png" alt=""></p>
<p>키값이 추가되면 번역이 되지않았다는 New로고가 뜨니까 해당부분을 번역해서 추가해주면된다.
물론 해당 스크린샷의 내 프로젝트는 아직 영문으로 변경하는 부분을 진행하지않아서 영문에 한글이써있으니 무시할것.</p>
<h3 id="팁">팁</h3>
<p>빌드를 했을 때, 자동으로 추가되는 키값들은 Text(&quot;&quot;) 의 내부에 포함되는 String들이다. 따라서 SwiftUI 프로젝트에서 대부분 텍스트들이 자동으로 추가 되겠지만 String값을 따로 쓸 때 로컬라이징이 안돼는 문제가 있다. 
특히 UIViewRepresentable 을 사용할때 String 에 로컬라이즈가 적용되지 않는다는 것!</p>
<p>String을 따로 로컬라이징할때</p>
<pre><code>String(localized: &quot;로컬라이즈 텍스트 키&quot;)</code></pre><p>이런식으로 사용해주면 빌드할 때 문제없이 자동으로 키가 추가됀다.</p>
<h3 id="단점">단점</h3>
<p>빌드할때 없는 값은 지워주고 키를 자동으로 생성해주므로 안드로이드 함께 관리되고있는 프로젝트에는 관리가 불가능할 수 있다. </p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Swift iso8601 to Date]]></title>
            <link>https://velog.io/@jiny_k/Swift-iso8601-to-Date</link>
            <guid>https://velog.io/@jiny_k/Swift-iso8601-to-Date</guid>
            <pubDate>Thu, 16 Nov 2023 00:02:02 GMT</pubDate>
            <description><![CDATA[<h2 id="date-to-iso8601">Date to ISO8601</h2>
<p>회사에서 작업하는데 날짜관련 통신을 String으로 한다고 되어있어서 보니 </p>
<pre><code>2023-11-15T07:46:07.364Z</code></pre><p>이런 데이터 형식으로 오는데 String타입. </p>
<p>내가 보내줄때는 </p>
<pre><code>let dateFormatter = ISO8601DateFormatter()
dateFormatter.formatOptions = [.withInternetDateTime, .withFractionalSeconds]
let iso8601String = dateFormatter.string(from: Date())
print(iso8601String) // &quot;2023-11-15T07:46:07.364Z&quot;</code></pre><p>이렇게 보내주면되고 </p>
<h2 id="iso8601-to-date">ISO8601 to Date</h2>
<p>받아서 쓸때는</p>
<pre><code>let string = &quot;2023-11-15T07:46:07.364Z&quot;
let iso8601DateFormatter = ISO8601DateFormatter()
iso8601DateFormatter.formatOptions = [.withInternetDateTime, .withFractionalSeconds]
let date = iso8601DateFormatter.date(from: string)

let dateFormatter2 = DateFormatter()
dateFormatter2.dateFormat = &quot;yyyy/MM/dd, HH:mm&quot;
print(dateFormatter2.string(for: date!)) // &quot;2023/11/15, 16:46&quot;</code></pre><p>이렇게 받아서 쓰면 된다. </p>
<p>그동안 unixTimeStamp로 작업하다보니 다소 생소한 부분이 있었지만 자바스크립트에서는 일반적인 시간값이라고 한다. </p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Realm 기초 - (Swift) Migration]]></title>
            <link>https://velog.io/@jiny_k/Realm-%EA%B8%B0%EC%B4%88-Swift-Migration</link>
            <guid>https://velog.io/@jiny_k/Realm-%EA%B8%B0%EC%B4%88-Swift-Migration</guid>
            <pubDate>Wed, 15 Nov 2023 05:04:54 GMT</pubDate>
            <description><![CDATA[<h2 id="object에-키값-추가">Object에 키값 추가</h2>
<p>Realm의 키값을 추가가하거나 타입을변경하는등 Object에 수정이 있을때는 꼭 마이그레이션 과정을 거쳐줘야하는데 저는 원래 이렇게 생긴 Object에 createdBy를 추가해줄거에요.</p>
<pre><code>import Foundation
import RealmSwift

class SomeModelObject: Object {
    @Persisted(primaryKey: true) var id: String
    @Persisted var title: String
    @Persisted var desc: String
    @Persisted var isDone: Bool
    @Persisted var date: Date
    @Persisted var optionType: List&lt;Int&gt;
    @Persisted var rootId: String

    convenience init(title: String) {
        self.init()
        self.id = UUID().uuidString
        self.title = title
        self.desc = &quot;&quot;
        self.isDone = false
        self.date = Date()
        self.optionType = List&lt;Int&gt;()
        self.rootId = &quot;&quot;
    }
}</code></pre><pre><code>import Foundation
import RealmSwift

class SomeModelObject: Object {
    @Persisted(primaryKey: true) var id: String
    @Persisted var title: String
    @Persisted var desc: String
    @Persisted var isDone: Bool
    @Persisted var date: Date
    @Persisted var optionType: List&lt;Int&gt;
    @Persisted var rootId: String
    @Persisted var createdBy: Date // 값 추가 

    convenience init(title: String) {
        self.init()
        self.id = UUID().uuidString
        self.title = title
        self.desc = &quot;&quot;
        self.isDone = false
        self.date = Date()
        self.optionType = List&lt;Int&gt;()
        self.rootId = &quot;&quot;
        self.createdBy = Date()
    }
}</code></pre><h2 id="변경된-object에-대한-마이그레이션">변경된 Object에 대한 마이그레이션</h2>
<p>그리고 AppDelegate를 통해 앱이 켜질때마다 Realm 버전을 확인하고 마이그레이션 시켜주면되는데 AppDelegate의 사이즈가 커지는것을 원하지 않으니 따로 Realm Migration을 담당할 Class를 만들어 줬어요.</p>
<pre><code>import RealmSwift
import Foundation

class RealmMigrationManager {

    // 싱글톤 인스턴스 생성
    static let shared = RealmMigrationManager()

    // 마이그레이션 메서드
    func performMigration() {
        let config = Realm.Configuration(
            // 현재 Realm 데이터베이스의 버전을 지정
            schemaVersion: 2,

            // 데이터베이스 업그레이드가 필요한 경우 호출되는 블록
            migrationBlock: { migration, oldSchemaVersion in
                if oldSchemaVersion &lt; 2 {
                    self.migrationV2(migration)
                }
            })

        // 새 구성으로 Realm 데이터베이스 열기
        Realm.Configuration.defaultConfiguration = config
        do {
            // 마이그레이션 수행
            _ = try Realm()
        } catch {
            // 마이그레이션 실패 시 처리할 내용
            print(&quot;Realm migration failed with error: \(error.localizedDescription)&quot;)
        }
    }

    private func migrationV2(_ migration: Migration) {
        // 스키마 버전 1에서 2로 마이그레이션 수행
        // 변경된 속성이나 새로운 모델을 추가할 수 있습니다.
        // 기존 객체들에 대한 업데이트
        migration.enumerateObjects(ofType: SomeModelObject.className()) { oldObject, newObject in
            //&#39;createdBy&#39; 속성 추가
            newObject?[&quot;createdBy&quot;] = Date()
            // 만약 이전 객체의 데이터를 기반으로 새로운 속성을 설정해야 한다면, oldObject를 사용할 수 있습니다.
        }
    }
}</code></pre><p>마이그레이션을 추가할수록 새로운 Realm에대한 버전별 예외처리는 계속 늘어날 수 밖에없으니 처음부터 신중하는게 좋을것 같아요!</p>
<h2 id="samplecode">SampleCode</h2>
<p><a href="https://github.com/Kim-Jiny/RealmSample">https://github.com/Kim-Jiny/RealmSample</a></p>
<blockquote>
</blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[Realm 기초 - (Swift)Realm 선언부터]]></title>
            <link>https://velog.io/@jiny_k/Realm-%EA%B8%B0%EC%B4%88-SwiftRealm-%EC%84%A0%EC%96%B8%EB%B6%80%ED%84%B0</link>
            <guid>https://velog.io/@jiny_k/Realm-%EA%B8%B0%EC%B4%88-SwiftRealm-%EC%84%A0%EC%96%B8%EB%B6%80%ED%84%B0</guid>
            <pubDate>Wed, 15 Nov 2023 02:09:38 GMT</pubDate>
            <description><![CDATA[<h2 id="realm-설치">Realm 설치</h2>
<p>Realm은 SPM을 지원합니다.</p>
<p><img src="https://velog.velcdn.com/images/jiny_k/post/b0a6a72e-4a22-4560-baa5-04b6dc7f02e7/image.png" alt=""></p>
<p>따라서 SPM으로 추가해주시면 보다 쉽게 사용하실 수 있습니다. </p>
<pre><code>import RealmSwift
</code></pre><p>으로 RealmSwift가 에러나지 않고 추가되면 성공.</p>
<h2 id="realm-모델-만들기">Realm 모델 만들기</h2>
<p>Realm에 저장할 Object를 하나 만들어 봅시다.</p>
<pre><code>import RealmSwift

class SomeModelObject: Object {
    @Persisted(primaryKey: true) var id: String
    @Persisted var title: String
    @Persisted var desc: String
    @Persisted var isDone: Bool
    @Persisted var date: Date
    @Persisted var optionType: List&lt;Int&gt;
    @Persisted var rootId: String

    convenience init(title: String) {
        self.init()
        self.id = UUID().uuidString
        self.title = title
        self.desc = &quot;&quot;
        self.isDone = false
        self.date = Date()
        self.optionType = List&lt;Int&gt;()
        self.rootId = &quot;&quot;
    }
}</code></pre><p>Realm은 Object자체를 하나의 테이블 처럼 보기때문에 한번 생성하면 키값을 추가할때 꼭 마이그레이션 작업을 해줘야합니다.</p>
<blockquote>
<p>** 마이그레이션 없이 키를 추가했다면 앱 크래시의 원인이 될 수 있습니다. ( 다음편에서 다룰예정 )**</p>
</blockquote>
<p>id 값을 저는 String으로 선언해서 uuid를 썼는데 기본으로 제공하는 ObjectId 타입을 사용하셔도 됩니다. <img src="https://velog.velcdn.com/images/jiny_k/post/73d66663-095f-430b-af64-94fca0d09a25/image.png" alt="">
모델은 모델을 품을 수 있습니다. </p>
<pre><code>import RealmSwift

class RootModelObject: Object {
    @Persisted(primaryKey: true) var key: String
    @Persisted var tasks = List&lt;SomeModelObject&gt;()

  convenience init(key: String, tasks: [SomeModelObject]) {
        self.init()
        self.key = key
        self.tasks.append(objectsIn: tasks)
    }
}
</code></pre><p>Realm은 [] 타입이 아닌 List&lt;&gt;을 지원하고 있습니다. </p>
<h2 id="data-꺼내기">Data 꺼내기</h2>
<p>값을 가지고 오고 싶을때는 </p>
<pre><code>func getRootModelObject(forKey key: String) -&gt; RootModelObject? {
    do {
      let realm = try Realm()
      return realm.object(ofType: RootModelObject.self, forPrimaryKey: key)
    }catch {
      print(&quot;Error: \(error)&quot;)
      return nil
    }
  }</code></pre><p>realm을 선언해서 해당하는Object를 Key로 찾아오면되고 </p>
<pre><code>    func getObjects() -&gt; Results&lt;RootModelObject&gt;? {
        do {
            let realm = try Realm()
            return realm.objects(RootModelObject.self)
        }catch {
            print(&quot;Error: \(error)&quot;)
            return nil
        }
    }
</code></pre><p>이렇게 Object자체가 있는지 확인해볼 수 있습니다. </p>
<h2 id="읽고-쓰고-지우고">읽고 쓰고 지우고</h2>
<p>아래는 읽고 쓰고 지우고의 예제 코드입니다. </p>
<pre><code>import Foundation
import RealmSwift

class RealmManager {
    static let shared = RealmManager()

    func getRootModelObject(forKey key: String) -&gt; RootModelObject? {
        do {
            let realm = try Realm()
            return realm.object(ofType: RootModelObject.self, forPrimaryKey: key)
        } catch {
            print(&quot;Error: \(error)&quot;)
            return nil
        }
    }

    func getObjects() -&gt; Results&lt;RootModelObject&gt;? {
        do {
            let realm = try Realm()
            return realm.objects(RootModelObject.self)
        } catch {
            print(&quot;Error: \(error)&quot;)
            return nil
        }
    }

    func isKeyAlreadyExists(key: String) -&gt; Bool {
        return getRootModelObject(forKey: key) != nil
    }

    func writeRootModelObject(forKey key: String, tasks: [SomeModelObject]) {
        do {
            let realm = try Realm()
            if let existingObject = getRootModelObject(forKey: key) {
                try realm.write {
                    for task in tasks {
                        existingObject.tasks.append(task)
                    }
                }
            } else {
                let rootObject = RootModelObject(key: key, tasks: tasks)
                try realm.write {
                    realm.add(rootObject)
                }
            }
        } catch {
            print(&quot;Error: \(error)&quot;)
        }
    }

    func deleteSomeModelObjectFromRootModel(rootKeyId: String, someModelId: String) {
        do {
            let realm = try Realm() // Realm 객체 생성
            if let rootObject = getRootModelObject(forKey: rootKeyId) {
                if let index = rootObject.tasks.firstIndex(where: { $0.id == someModelId }) {
                    try realm.write {
                        rootObject.tasks.remove(at: index)
                    }
                }
            }
        } catch {
            print(&quot;Error: \(error)&quot;)
        }
    }
}</code></pre><p>자주쓰는 처리들은 RealmManager을 만들어서 처리하면 더 쉽게 수정할 수 있습니다. </p>
<h2 id="sample-project">Sample Project</h2>
<p>해당 코드는 <a href="https://github.com/Kim-Jiny/RealmSample">https://github.com/Kim-Jiny/RealmSample</a> 에서 확인하실 수 있습니다. </p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Realm 기초 - Realm 눈으로 확인하기]]></title>
            <link>https://velog.io/@jiny_k/Realm-%EA%B8%B0%EC%B4%88-Realm-%EB%88%88%EC%9C%BC%EB%A1%9C-%ED%99%95%EC%9D%B8%ED%95%98%EA%B8%B0</link>
            <guid>https://velog.io/@jiny_k/Realm-%EA%B8%B0%EC%B4%88-Realm-%EB%88%88%EC%9C%BC%EB%A1%9C-%ED%99%95%EC%9D%B8%ED%95%98%EA%B8%B0</guid>
            <pubDate>Wed, 15 Nov 2023 01:25:19 GMT</pubDate>
            <description><![CDATA[<p>회사에서 옜날 프로젝트를 되살리면서 옛 개발자들이 만들어놓은 앱을 열었는데 앱이 실행조차 되지 않더라고요... </p>
<p>이전회사에서도 realm은 많이 쓰던건데도 왜 어려운지
기초부터 내 앱은 왜 realm에서 자꾸 죽는지.. 하나하나 알아보겠습니다. </p>
<p>먼저 Realm을 쓰는 이유는 가볍고 빠르고 암호화가 됩니다. 
UserDefault랑 비교하면 UserDefault는 가볍게 중요하지않은 정보들을 저장하는데 좋지만 양이 많아지면 무거워지고 보안도 취약하므로 무겁거나 중요한 정보는 realm을 이용하는게 좋습니다. </p>
<blockquote>
<p>realm에 대한 자세한 정보는 아래 링크를 확인해주세요.
<a href="https://www.mongodb.com/docs/realm/sdk/swift/realm-database/">https://www.mongodb.com/docs/realm/sdk/swift/realm-database/</a></p>
</blockquote>
<h2 id="realm-눈으로-데이터-확인하기">Realm 눈으로 데이터 확인하기</h2>
<p>먼저 내 앱에대한 realm Data를 눈으로 확인 하려면 XCode에서 command+shift+2 를 눌러서 디바이스 리스트를 열어줍니다. <img src="https://velog.velcdn.com/images/jiny_k/post/691e8167-a40e-464c-9b61-cc57fcd378cf/image.png" alt="">
 상위의 윈도우 탭을 이용해서 Devices and Simulators를 눌러 이동해줘도 됩니다. <img src="https://velog.velcdn.com/images/jiny_k/post/6a967f3f-b1f5-4fc4-82a9-aef04d3e1009/image.png" alt=""></p>
<p>하면 이렇게 폰에 설치된 개발자 앱들이 보이는데 여기서 원하는 앱을 눌러서 ... 버튼을 통해 Download Container... 을 누르면 됩니다. </p>
<p>(예전버전에서는 그냥 앱눌렀을때 내부파일 중에 realm파일만 복사해올수 있었는데 Xcode15로 올리면서 UI가 바뀐건지 내부파일을 볼수있는 창이 없어진것 같더라고요 )
<img src="https://velog.velcdn.com/images/jiny_k/post/d9ab6245-b365-4d10-94cd-3a1de22d3378/image.png" alt="">
다운받은 파일을 Show Package Contents를 통해 내부를 들여다보면
<img src="https://velog.velcdn.com/images/jiny_k/post/6b07dd31-141b-470a-a43e-8ebd619cee7e/image.png" alt="">
안에 있는 Realm파일을 복사해서 패키지 밖으로 끄집어내줍니다. </p>
<p><img src="https://velog.velcdn.com/images/jiny_k/post/6e31b2c2-3ae5-4d5a-8fcd-168fcd040356/image.png" alt="">
 이제 여기서 보이는 default.realm이라는 파일을 열어볼건데 Realm Studio를 설치해두면 편하게 볼 수 있습니다. 
 <a href="https://studio-releases.realm.io/?_ga=2.70055698.323270583.1700009798-95780169.1697613972">https://studio-releases.realm.io/?_ga=2.70055698.323270583.1700009798-95780169.1697613972</a>
 <img src="https://velog.velcdn.com/images/jiny_k/post/ca8ca92e-c439-4c0b-b07a-8137a515a3a2/image.png" alt="">
 우측의 Realm Browser이 아닌 중앙의 Realm Studio를 설치해주세요.<img src="https://velog.velcdn.com/images/jiny_k/post/ec82023f-73e2-47db-8d5c-5f755af91900/image.png" alt=""></p>
<p>이제 Open Realm file에 default.realm (또는 이름이 .realm으로 끝나는 파일) 을 넣고 열면 눈으로 DB를 눈으로 볼 수 있습니다.<img src="https://velog.velcdn.com/images/jiny_k/post/4284b8ec-401d-48bb-a933-02739b2b0145/image.png" alt=""></p>
<p>직접 쿼리를 입력해서 데이터를 뽑아 볼수도 있구요. </p>
<p>자꾸 realm에서 크래시가나는데 데이터가 없다는 얘기를 한다면 눈으로 확인해보세요 
(물론 print 찍어보는게 더 빠를 수 있습니다.ㅋㅋ)</p>
]]></description>
        </item>
    </channel>
</rss>