<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>iOYES</title>
    <link>https://green1229.tistory.com/</link>
    <description>Green is Green </description>
    <language>ko</language>
    <pubDate>Tue, 15 Sep 2026 11:28:43 +0900</pubDate>
    <generator>TISTORY</generator>
    <ttl>100</ttl>
    <managingEditor>GREEN.1229</managingEditor>
    <image>
      <title>iOYES</title>
      <url>https://tistory1.daumcdn.net/tistory/4326025/attach/5dc0ba3d4d3c460d8c291fa6a8cfb2d1</url>
      <link>https://green1229.tistory.com</link>
    </image>
    <item>
      <title>SwiftUI - Canvas</title>
      <link>https://green1229.tistory.com/636</link>
      <description>&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;안녕하세요. &lt;span style=&quot;color: #409d00;&quot;&gt;&lt;b&gt;그린&lt;/b&gt;&lt;/span&gt;입니다  &lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;이번 포스팅에서는 &lt;b&gt;&lt;span style=&quot;background-color: #9feec3;&quot;&gt;SwiftUI의&lt;/span&gt; Canvas 컴포넌트&lt;/b&gt;에 대해 애플 공식 문서를 기준으로 정리해보겠습니다  &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;123123.001.jpeg&quot; data-origin-width=&quot;400&quot; data-origin-height=&quot;400&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bEPguC/dJMcacq7Oeb/1jr25Rptwqdx4NWNHp8KnK/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bEPguC/dJMcacq7Oeb/1jr25Rptwqdx4NWNHp8KnK/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bEPguC/dJMcacq7Oeb/1jr25Rptwqdx4NWNHp8KnK/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbEPguC%2FdJMcacq7Oeb%2F1jr25Rptwqdx4NWNHp8KnK%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;400&quot; height=&quot;400&quot; data-filename=&quot;123123.001.jpeg&quot; data-origin-width=&quot;400&quot; data-origin-height=&quot;400&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h2 style=&quot;border-left: 4px solid #3a8c28; padding-left: 12px; margin-top: 32px;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;Intro&lt;/span&gt;&lt;/b&gt;&lt;/h2&gt;
&lt;div style=&quot;background: #f2f8ee; border-radius: 10px; padding: 16px 20px; margin: 16px 0;&quot;&gt;
&lt;p style=&quot;margin: 4px 0;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;&lt;b&gt;프레임워크:&lt;/b&gt; SwiftUI&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;margin: 4px 0;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;&lt;b&gt;지원 버전:&lt;/b&gt; iOS 15 / macOS 12 / watchOS 8 이상&lt;/span&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;h2 style=&quot;border-left: 4px solid #3a8c28; padding-left: 12px; margin-top: 32px;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;Canvas?&lt;/span&gt;&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;일반 SwiftUI 뷰(&lt;code&gt;Circle&lt;/code&gt;, &lt;code&gt;Rectangle&lt;/code&gt;, &lt;code&gt;Path&lt;/code&gt;)를 여러 개 겹쳐 그리면, SwiftUI는 그 뷰들을 실제 뷰 트리 노드로 유지해요(retained mode). &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;상태가 바뀌면 diffing해서 필요한 부분만 다시 그리죠.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;&lt;code&gt;Canvas&lt;/code&gt;는 이 방식을 버려요. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;대신 &lt;b&gt;클로저 하나&lt;/b&gt;를 받아서, 매 프레임 그 클로저를 통째로 다시 실행해요. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;클로저 안에서 &lt;code&gt;GraphicsContext&lt;/code&gt;라는 그리기 도구에게 순서대로 명령을 내리는 방식이라 즉시 모드(immediate mode)라고 불러요.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000; text-align: start;&quot;&gt;Canvas 뷰는 매 프레임 renderer 클로저 &lt;/span&gt;(inout GraphicsContext, CGSize) -&amp;gt; Void&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000; text-align: start;&quot;&gt;를 실행해 GraphicsContext를 통해 픽셀을 직접 그립니다. &lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000; text-align: start;&quot;&gt;개별 도형은 뷰 트리에 남지 않아요.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 style=&quot;border-left: 4px solid #3a8c28; padding-left: 12px; margin-top: 32px;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt; 기본적인 사용법 &amp;mdash; stroke&lt;/span&gt;&lt;/b&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;&lt;/span&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;애플 공식 문서의 첫 예제가 아래와 같습니다.&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;/blockquote&gt;
&lt;pre class=&quot;less&quot; style=&quot;background: #1e1e1e; color: #d4d4d4; padding: 16px; border-radius: 8px; overflow: auto;&quot;&gt;&lt;code&gt;Canvas { context, size in
    context.stroke(
        Path(ellipseIn: CGRect(origin: .zero, size: size)),
        with: .color(.green),
        lineWidth: 4)
}
.frame(width: 300, height: 200)
.border(Color.blue)&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;&lt;code&gt;context&lt;/code&gt;: &lt;code&gt;GraphicsContext&lt;/code&gt; &amp;mdash; 여기다 대고 &quot;그려라&quot; 명령을 내림&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;&lt;code&gt;size&lt;/code&gt;: 캔버스가 차지한 실제 &lt;code&gt;CGSize&lt;/code&gt; &amp;mdash; 이 크기에 맞춰 좌표를 계산&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;&lt;code&gt;Path(ellipseIn:)&lt;/code&gt;: 캔버스 크기에 딱 맞는 타원 경로&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;&lt;code&gt;.stroke(_:with:lineWidth:)&lt;/code&gt;: 경로의 윤곽선만 그림 (채우기 아님)&lt;/span&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img style=&quot;max-width: 100%; border-radius: 8px;&quot; src=&quot;data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMzIwIiBoZWlnaHQ9IjIyMCIgdmlld0JveD0iMCAwIDMyMCAyMjAiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+CjxyZWN0IHdpZHRoPSIzMjAiIGhlaWdodD0iMjIwIiBmaWxsPSIjZmFmYWZhIi8+CjxyZWN0IHg9IjEwIiB5PSIxMCIgd2lkdGg9IjMwMCIgaGVpZ2h0PSIyMDAiIGZpbGw9Im5vbmUiIHN0cm9rZT0iIzM0NzhERCIgc3Ryb2tlLXdpZHRoPSIyIi8+CjxlbGxpcHNlIGN4PSIxNjAiIGN5PSIxMTAiIHJ4PSIxNDgiIHJ5PSI5OCIgZmlsbD0ibm9uZSIgc3Ryb2tlPSIjNENBRjUwIiBzdHJva2Utd2lkdGg9IjQiLz4KPC9zdmc+Cg==&quot; alt=&quot;stroke 예제 렌더링 결과&quot; /&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: center; color: #888888;&quot; data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 style=&quot;border-left: 4px solid #3a8c28; padding-left: 12px; margin-top: 32px;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;GraphicsContext의 핵심 규칙 &amp;mdash; &quot;순서가 상태다&quot;&lt;/span&gt;&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;&lt;code&gt;GraphicsContext&lt;/code&gt;는 그냥 그리기 함수 모음이 아니라, &lt;b&gt;자기 자신이 상태(state)를 갖는 객체&lt;/b&gt;예요. &lt;code&gt;opacity&lt;/code&gt;, &lt;code&gt;blendMode&lt;/code&gt;, clip, transform 같은 값을 바꾸면 &lt;b&gt;그 이후에 실행되는 그리기 명령에만&lt;/b&gt; 영향을 줘요. 이미 그려진 건 안 바뀝니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;애플 공식 문서가 정확히 이걸로 예제를 들어요.&lt;/span&gt;&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre class=&quot;reasonml&quot; style=&quot;background: #1e1e1e; color: #d4d4d4; padding: 16px; border-radius: 8px; overflow: auto;&quot;&gt;&lt;code&gt;let halfSize = size.applying(CGAffineTransform(scaleX: 0.5, y: 0.5))
context.clip(to: Path(CGRect(origin: .zero, size: halfSize)))   // 1. 먼저 클립
context.fill(
    Path(ellipseIn: CGRect(origin: .zero, size: size)),
    with: .color(.green))                                        // 2. 그 다음 채우기&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;절반 크기의 사각형으로 먼저 클립을 걸어두면, 그 뒤에 그리는 타원은 클립 영역 밖으로 나간 부분이 안 보여요. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;반대로 fill을 먼저 하고 clip을 나중에 걸면, 클립은 &quot;이후 연산에만&quot; 적용되는 규칙 때문에 이미 그려진 타원엔 아무 영향이 없습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;img style=&quot;max-width: 100%; border-radius: 8px;&quot; src=&quot;data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iNjQwIiBoZWlnaHQ9IjI0MCIgdmlld0JveD0iMCAwIDY0MCAyNDAiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+CjxyZWN0IHdpZHRoPSI2NDAiIGhlaWdodD0iMjQwIiBmaWxsPSIjZmFmYWZhIi8+CjxkZWZzPjxjbGlwUGF0aCBpZD0icXVhZENsaXAiPjxyZWN0IHg9IjMwIiB5PSIyMCIgd2lkdGg9IjE1MCIgaGVpZ2h0PSIxMDAiLz48L2NsaXBQYXRoPjwvZGVmcz4KPHJlY3QgeD0iMzAiIHk9IjIwIiB3aWR0aD0iMzAwIiBoZWlnaHQ9IjIwMCIgZmlsbD0ibm9uZSIgc3Ryb2tlPSIjYmJiIiBzdHJva2Utd2lkdGg9IjEiLz4KPGcgY2xpcC1wYXRoPSJ1cmwoI3F1YWRDbGlwKSI+PGVsbGlwc2UgY3g9IjE4MCIgY3k9IjEyMCIgcng9IjE0OCIgcnk9Ijk4IiBmaWxsPSIjNENBRjUwIi8+PC9nPgo8dGV4dCB4PSIxODAiIHk9IjIzOCIgZm9udC1zaXplPSIxMyIgZmlsbD0iIzg4OCIgdGV4dC1hbmNob3I9Im1pZGRsZSI+Y2xpcCB0byBmaWxsIChxdWFkcmFudCBvbmx5KTwvdGV4dD4KPHJlY3QgeD0iMzkwIiB5PSIyMCIgd2lkdGg9IjE1MCIgaGVpZ2h0PSIxMDAiIGZpbGw9Im5vbmUiIHN0cm9rZT0iI2JiYiIgc3Ryb2tlLXdpZHRoPSIxIi8+CjxlbGxpcHNlIGN4PSI1NDAiIGN5PSIxMjAiIHJ4PSI3NCIgcnk9IjQ5IiBmaWxsPSIjNENBRjUwIiBvcGFjaXR5PSIwLjkiLz4KPHRleHQgeD0iNDY1IiB5PSIyMzgiIGZvbnQtc2l6ZT0iMTMiIGZpbGw9IiM4ODgiIHRleHQtYW5jaG9yPSJtaWRkbGUiPmZpbGwgdG8gY2xpcCAoY2xpcCBpbmVmZmVjdGl2ZSk8L3RleHQ+Cjwvc3ZnPgo=&quot; alt=&quot;clip 순서에 따른 렌더링 차이&quot; /&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 style=&quot;border-left: 4px solid #3a8c28; padding-left: 12px; margin-top: 32px;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;context는 값 타입 &amp;mdash; 복사해서 독립적으로 쓸 수 있다&lt;/span&gt;&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;&lt;code&gt;GraphicsContext&lt;/code&gt;는 &lt;code&gt;struct&lt;/code&gt;예요. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;그래서 &lt;b&gt;복사하면 상태가 통째로 복제&lt;/b&gt;돼요. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;원본과 복사본은 서로 다른 state(clip, opacity 등)를 가질 수 있지만, &lt;b&gt;같은 레이어&lt;/b&gt;에 그림을 그려요. 즉, &quot;복사본에만 클립을 걸고 그리기&quot;가 가능해요.&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;reasonml&quot; style=&quot;background: #1e1e1e; color: #d4d4d4; padding: 16px; border-radius: 8px; overflow: auto;&quot;&gt;&lt;code&gt;var maskedContext = context          // 상태를 통째로 복사
let halfSize = size.applying(CGAffineTransform(scaleX: 0.5, y: 0.5))
maskedContext.clip(to: Path(CGRect(origin: .zero, size: halfSize)))
maskedContext.fill(
    Path(ellipseIn: CGRect(origin: .zero, size: size)),
    with: .color(.green))            // 이 fill만 클립의 영향을 받음

// 원본 context는 클립이 안 걸린 상태 그대로
context.fill(
    Path(CGRect(origin: origin, size: halfSize)),
    with: .color(.blue))              // 클립 영향 없이 파란 사각형 그림&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;이 패턴은 &quot;특정 도형에만 마스크/필터를 걸고 싶은데, 나머지 그리기엔 영향을 주고 싶지 않을 때&quot; 자주 씁니다.&lt;/span&gt;&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 style=&quot;border-left: 4px solid #3a8c28; padding-left: 12px; margin-top: 32px;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;좌표계 변환 &amp;mdash; transform&lt;/span&gt;&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;&lt;code&gt;GraphicsContext&lt;/code&gt;는 내부에 &lt;code&gt;CGAffineTransform&lt;/code&gt;을 갖고 있고, &lt;code&gt;scaleBy&lt;/code&gt;/&lt;code&gt;rotate&lt;/code&gt;/&lt;code&gt;translateBy&lt;/code&gt;/&lt;code&gt;concatenate&lt;/code&gt; 메서드는 전부 이 &lt;code&gt;transform&lt;/code&gt;을 갱신하는 편의 함수예요.&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;reasonml&quot; style=&quot;background: #1e1e1e; color: #d4d4d4; padding: 16px; border-radius: 8px; overflow: auto;&quot;&gt;&lt;code&gt;context.translateBy(x: size.width / 2, y: size.height / 2)  // 원점을 중앙으로
context.rotate(by: .degrees(45))                              // 45도 회전
context.scaleBy(x: 1.5, y: 1.5)                                // 1.5배 확대&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;공식 문서 표현 그대로, &lt;code&gt;rotate(by:)&lt;/code&gt;를 호출하는 건 사실 아래 코드를 대신 해주는 슈가 문법이에요.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre class=&quot;pgsql&quot; style=&quot;background: #1e1e1e; color: #d4d4d4; padding: 16px; border-radius: 8px; overflow: auto;&quot;&gt;&lt;code&gt;transform = transform.rotated(by: angle.radians)&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000; text-align: start;&quot;&gt;이 변환들도 순서가 중요해요. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;translate&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000; text-align: start;&quot;&gt; 후 &lt;/span&gt;rotate&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000; text-align: start;&quot;&gt;와 &lt;/span&gt;rotate&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000; text-align: start;&quot;&gt; 후 &lt;/span&gt;translate&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000; text-align: start;&quot;&gt;는 결과가 다릅니다. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000; text-align: start;&quot;&gt;앞서 설명한 &quot;이후 연산에만 적용&quot; 규칙이 여기서도 그대로 적용돼요.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 style=&quot;border-left: 4px solid #3a8c28; padding-left: 12px; margin-top: 32px;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;블렌드 모드와 필터&lt;/span&gt;&lt;/b&gt;&lt;/h2&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;opacity, blendMode도 같은 원리로 동작해요.&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;/blockquote&gt;
&lt;pre class=&quot;ini&quot; style=&quot;background: #1e1e1e; color: #d4d4d4; padding: 16px; border-radius: 8px; overflow: auto;&quot;&gt;&lt;code&gt;context.blendMode = .destinationOut   // 이후 그리는 도형으로 배경을 &quot;지운다&quot;
context.opacity = 0.5                  // 이후 그리는 것들이 반투명해짐&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;&lt;code&gt;addFilter(_:options:)&lt;/code&gt;로는 이미지 처리 필터도 이후 그리기에 적용할 수 있어요. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;예를 들어 블러 효과는 다음처럼 씁니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre class=&quot;reasonml&quot; style=&quot;background: #1e1e1e; color: #d4d4d4; padding: 16px; border-radius: 8px; overflow: auto;&quot;&gt;&lt;code&gt;context.addFilter(.blur(radius: 8))&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;&lt;code&gt;GraphicsContext.Filter&lt;/code&gt;에는 이 외에도 &lt;code&gt;alphaThreshold&lt;/code&gt;, 그리고 &lt;code&gt;ShadowOptions&lt;/code&gt;를 활용하는 그림자 필터 등 다양한 케이스가 존재합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 style=&quot;border-left: 4px solid #3a8c28; padding-left: 12px; margin-top: 32px;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;SwiftUI 뷰를 통째로 그리기 &amp;mdash; symbols&lt;/span&gt;&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;&lt;code&gt;Canvas&lt;/code&gt;가 효율적인 이유 중 하나는, 진짜 SwiftUI 뷰를 &quot;드로잉 재료&quot;로 등록해서 원하는 위치에 여러 번 찍어낼 수 있다는 거예요.&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;reasonml&quot; style=&quot;background: #1e1e1e; color: #d4d4d4; padding: 16px; border-radius: 8px; overflow: auto;&quot;&gt;&lt;code&gt;Canvas { context, size in
    for i in 0..&amp;lt;20 {
        if let symbol = context.resolveSymbol(id: i) {
            let point = CGPoint(x: Double(i) * 15, y: 50)
            context.draw(symbol, at: point, anchor: .center)
        }
    }
} symbols: {
    ForEach(0..&amp;lt;20) { i in
        Circle()
            .fill(.blue)
            .frame(width: 10, height: 10)
            .tag(i)   // resolveSymbol(id:)에서 이 id로 찾음
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;&lt;code&gt;symbols&lt;/code&gt; 클로저에 등록된 뷰들은 &lt;code&gt;.tag(_:)&lt;/code&gt;로 붙인 id를 통해 &lt;code&gt;resolveSymbol(id:)&lt;/code&gt;로 꺼내 쓸 수 있어요. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;이렇게 꺼낸 &lt;code&gt;ResolvedSymbol&lt;/code&gt;은 &lt;b&gt;해상도 독립적&lt;/b&gt;이라, 같은 심볼을 수십&amp;middot;수백 번 다른 위치에 찍어도 성능이 안정적이에요. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;파티클, 포인트 클라우드, 커스텀 차트 마커 같은 걸 그릴 때 정확히 이 패턴을 씁니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 style=&quot;border-left: 4px solid #3a8c28; padding-left: 12px; margin-top: 32px;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;텍스트와 이미지 &amp;mdash; resolve&lt;/span&gt;&lt;/b&gt;&lt;/h2&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;Text나 Image도 바로는 못 그리고, 먼저 환경(폰트, 색상 스킴 등)에 맞춰 &quot;고정&quot;시켜야 해요.&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;/blockquote&gt;
&lt;pre class=&quot;maxima&quot; style=&quot;background: #1e1e1e; color: #d4d4d4; padding: 16px; border-radius: 8px; overflow: auto;&quot;&gt;&lt;code&gt;Canvas { context, size in
    let resolvedText = context.resolve(Text(&quot;Hello&quot;).font(.title))
    context.draw(resolvedText, at: CGPoint(x: size.width/2, y: 20), anchor: .top)
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;&lt;code&gt;resolve(_:)&lt;/code&gt;가 &lt;code&gt;Text&lt;/code&gt;/&lt;code&gt;Image&lt;/code&gt;를 각각 &lt;code&gt;ResolvedText&lt;/code&gt;/&lt;code&gt;ResolvedImage&lt;/code&gt;로 바꿔주는데, 이 과정에서 &lt;code&gt;context.environment&lt;/code&gt;(디스플레이 해상도, 컬러 스킴 등)를 참조해요.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 style=&quot;border-left: 4px solid #3a8c28; padding-left: 12px; margin-top: 32px;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;withCGContext&lt;/span&gt;&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;정말 세밀한 제어가 필요하면 &lt;code&gt;withCGContext(content:)&lt;/code&gt;로 진짜 Core Graphics &lt;code&gt;CGContext&lt;/code&gt;를 빌려서 그릴 수도 있어요. &lt;code&gt;GraphicsContext&lt;/code&gt;가 지원 안 하는 연산이 필요할 때 쓰는 탈출구예요.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 style=&quot;border-left: 4px solid #3a8c28; padding-left: 12px; margin-top: 32px;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;언제 Canvas를 써야 하나 &amp;mdash; 공식 문서의 트레이드오프&lt;/span&gt;&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;애플 문서가 명시적으로 경고하는 부분이에요.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;border-left: 4px solid #3a8c28; background: #f2f8ee; padding: 8px 16px; margin: 16px 0;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;Canvas doesn't offer interactivity or accessibility for individual elements, including for views that you pass in as symbols.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;즉, &lt;code&gt;symbols&lt;/code&gt;로 진짜 &lt;code&gt;Button&lt;/code&gt;을 넣어도 &lt;b&gt;탭 이벤트가 안 먹고, VoiceOver도 개별 요소를 인식 못 해요.&lt;/b&gt; &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;대신 다음 기준으로 판단하면 됩니다.&lt;/span&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;동적 데이터가 많고, 도형 개수가 유동적인 복잡한 드로잉일수록 유리 (뷰 트리 오버헤드가 없으니까)&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;텍스트 위주이거나 사용자와 상호작용해야 하는 UI는 Canvas가 아니라 일반 SwiftUI 뷰로&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 style=&quot;border-left: 4px solid #3a8c28; padding-left: 12px; margin-top: 32px;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;Conclusion&lt;/span&gt;&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;&lt;code&gt;Canvas&lt;/code&gt;는 SwiftUI 뷰 트리를 포기하는 대신, 매 프레임 &lt;code&gt;GraphicsContext&lt;/code&gt;에 명령을 순서대로 내려서 즉시 픽셀을 그리는 고성능 드로잉 도구예요. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;상태(clip/opacity/transform/filter)는 항상 &quot;이후 연산에만&quot; 적용된다는 규칙 하나만 기억하면, 나머지 API는 다 이 규칙의 응용이라고 볼 수 있습니다  &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 style=&quot;border-left: 4px solid #3a8c28; padding-left: 12px; margin-top: 32px;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;References&lt;/span&gt;&lt;/b&gt;&lt;/h2&gt;
&lt;figure id=&quot;og_1789197019238&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;Canvas | Apple Developer Documentation&quot; data-og-description=&quot;A view type that supports immediate mode drawing.&quot; data-og-host=&quot;developer.apple.com&quot; data-og-source-url=&quot;https://developer.apple.com/documentation/swiftui/canvas&quot; data-og-url=&quot;https://developer.apple.com/documentation/swiftui/canvas&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/nBJWZ/dJMb8ZvVHG8/cnrHzx5mTJSSJW0arOPxnK/img.jpg?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630,https://scrap.kakaocdn.net/dn/RCZhJ/dJMb9c9RRvJ/0I4SSazJUki5c3FJSiud1k/img.jpg?width=1024&amp;amp;height=512&amp;amp;face=0_0_1024_512&quot;&gt;&lt;a href=&quot;https://developer.apple.com/documentation/swiftui/canvas&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://developer.apple.com/documentation/swiftui/canvas&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/nBJWZ/dJMb8ZvVHG8/cnrHzx5mTJSSJW0arOPxnK/img.jpg?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630,https://scrap.kakaocdn.net/dn/RCZhJ/dJMb9c9RRvJ/0I4SSazJUki5c3FJSiud1k/img.jpg?width=1024&amp;amp;height=512&amp;amp;face=0_0_1024_512');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;Canvas | Apple Developer Documentation&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;A view type that supports immediate mode drawing.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;developer.apple.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;figure id=&quot;og_1789197020598&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;GraphicsContext | Apple Developer Documentation&quot; data-og-description=&quot;An immediate mode drawing destination, and its current state.&quot; data-og-host=&quot;developer.apple.com&quot; data-og-source-url=&quot;https://developer.apple.com/documentation/swiftui/graphicscontext&quot; data-og-url=&quot;https://developer.apple.com/documentation/swiftui/graphicscontext&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/lQL24/dJMb8QeGtDY/hco9sSFIkpXs6okzSKkbK1/img.jpg?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630,https://scrap.kakaocdn.net/dn/uL5P5/dJMb8VNQgpb/KbjT1p9ukjcyQpdXbHPSdk/img.jpg?width=1024&amp;amp;height=512&amp;amp;face=0_0_1024_512&quot;&gt;&lt;a href=&quot;https://developer.apple.com/documentation/swiftui/graphicscontext&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://developer.apple.com/documentation/swiftui/graphicscontext&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/lQL24/dJMb8QeGtDY/hco9sSFIkpXs6okzSKkbK1/img.jpg?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630,https://scrap.kakaocdn.net/dn/uL5P5/dJMb8VNQgpb/KbjT1p9ukjcyQpdXbHPSdk/img.jpg?width=1024&amp;amp;height=512&amp;amp;face=0_0_1024_512');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;GraphicsContext | Apple Developer Documentation&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;An immediate mode drawing destination, and its current state.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;developer.apple.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>SwiftUI</category>
      <category>Canvas</category>
      <category>ios</category>
      <category>SWIFT</category>
      <category>swiftUI</category>
      <author>GREEN.1229</author>
      <guid isPermaLink="true">https://green1229.tistory.com/636</guid>
      <comments>https://green1229.tistory.com/636#entry636comment</comments>
      <pubDate>Sat, 12 Sep 2026 16:11:41 +0900</pubDate>
    </item>
    <item>
      <title>[SE-0544] Mutation and consumption in non-Copyable type deinits</title>
      <link>https://green1229.tistory.com/635</link>
      <description>&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;안녕하세요. &lt;span style=&quot;color: #409d00;&quot;&gt;&lt;b&gt;그린&lt;/b&gt;&lt;/span&gt;입니다  &lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;이번 포스팅에서는 &lt;span style=&quot;background-color: #9feec3;&quot;&gt;&lt;b&gt;SE-0544 &amp;mdash; noncopyable 타입 deinit에서의 mutation과 consumption에 대해 정리&lt;/b&gt;&lt;/span&gt;해보겠습니다  &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;123123.001.jpeg&quot; data-origin-width=&quot;400&quot; data-origin-height=&quot;400&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/OCJvk/dJMcagfGIHE/xpi1k8fwKTGejkRcaFqE60/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/OCJvk/dJMcagfGIHE/xpi1k8fwKTGejkRcaFqE60/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/OCJvk/dJMcagfGIHE/xpi1k8fwKTGejkRcaFqE60/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FOCJvk%2FdJMcagfGIHE%2Fxpi1k8fwKTGejkRcaFqE60%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;400&quot; height=&quot;400&quot; data-filename=&quot;123123.001.jpeg&quot; data-origin-width=&quot;400&quot; data-origin-height=&quot;400&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h2 style=&quot;border-left: 4px solid #3a8c28; padding-left: 12px; margin-top: 32px;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;Intro&lt;/span&gt;&lt;/b&gt;&lt;/h2&gt;
&lt;div style=&quot;background: #f2f8ee; border-radius: 10px; padding: 16px 20px; margin: 16px 0;&quot;&gt;
&lt;p style=&quot;margin: 4px 0;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;&lt;b&gt;Proposal:&lt;/b&gt; SE-0544&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;margin: 4px 0;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;&lt;b&gt;Author:&lt;/b&gt; Joe Groff&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;margin: 4px 0;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;&lt;b&gt;Review Manager:&lt;/b&gt; John McCall&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;margin: 4px 0;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;&lt;b&gt;Status:&lt;/b&gt; Accepted&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;margin: 4px 0;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;&lt;b&gt;Implementation:&lt;/b&gt; swiftlang/swift#90836&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;noncopyable 타입은 &lt;code&gt;deinit&lt;/code&gt;을 정의해서 생명주기가 끝날 때 소유하고 있던 리소스를 정리할 수 있어요. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;&lt;b&gt;하지만 이 제안 이전에는 &lt;code&gt;deinit&lt;/code&gt; 본문 안에서 &lt;code&gt;self&lt;/code&gt;가 immutable하고 오직 borrow만 가능&lt;/b&gt;했어요. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;이 제안은&lt;b&gt; &lt;code&gt;deinit&lt;/code&gt;이 &lt;code&gt;self&lt;/code&gt;의 필드를 mutate하거나 consume할 수 있게 허용하되, value resurrection 문제를 피하기 위해 &lt;code&gt;self&lt;/code&gt; 전체를 하나의 값으로서 mutate하거나 consume하는 건 여전히 막아두자고 제안&lt;/b&gt;합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 style=&quot;border-left: 4px solid #3a8c28; padding-left: 12px; margin-top: 32px;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;Motivation&lt;/span&gt;&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;많은 noncopyable 타입 구현체는 리소스를 소유한 다른 noncopyable 값들로 구성돼요. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;그 구성 요소들이 전체 값의 정리 과정에서 어떻게 consume되는지 제어하고 싶은 건 자연스러운 요청일겁니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre class=&quot;nimrod&quot; style=&quot;background: #1e1e1e; color: #d4d4d4; padding: 16px; border-radius: 8px; overflow: auto;&quot;&gt;&lt;code&gt;struct File: ~Copyable {
  consuming func close() {...}
}

struct Buffer: ~Copyable {
  borrowing func flush(to file: borrowing File) {...}
  consuming func release() {...}
}

struct BufferedFile: ~Copyable {
  let file: File
  let buffer: Buffer
  
  deinit {
    // Flush then close the buffer
    buffer.flush(to: file)
    buffer.release()
    // Then close the file
    file.close()
  }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;비슷한 맥락에서, deinit이 정리 과정의 일부로 mutating 메서드에 담아둔 코드를 쓰고 싶을 수도 있어요.&lt;/span&gt;&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 style=&quot;border-left: 4px solid #3a8c28; padding-left: 12px; margin-top: 32px;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;Proposed Solution&lt;/span&gt;&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;&lt;code&gt;deinit&lt;/code&gt;이 &lt;code&gt;self&lt;/code&gt;의 필드를 mutate하고 consume할 수 있도록 허용하자고 제안합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 style=&quot;border-left: 4px solid #3a8c28; padding-left: 12px; margin-top: 32px;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;Detailed Design&lt;/span&gt;&lt;/b&gt;&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;&quot;resurrection&quot;과 의도치 않은 재귀 피하기&lt;/span&gt;&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;noncopyable 타입의 &lt;code&gt;deinit&lt;/code&gt;은 값의 소유권을 가진 컨텍스트 중에서도 독특한 존재예요. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;다른 소유 컨텍스트라면 값을 암묵적으로 &lt;code&gt;deinit&lt;/code&gt;을 호출해서 파괴하겠지만, &lt;code&gt;deinit&lt;/code&gt; 자신은 당연히 그럴 수 없죠.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;&lt;code&gt;deinit&lt;/code&gt;은 오직 값을 구성하는 저장 프로퍼티나 채워진 enum case만 파괴합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;&lt;b&gt;만약 &lt;code&gt;deinit&lt;/code&gt;이 &lt;code&gt;self&lt;/code&gt;를 consuming이나 mutating 연산에 통째로 넘길 수 있다면, 그 callee의 생명주기가 끝나는 시점에 다시 &lt;code&gt;deinit&lt;/code&gt;이 호출될 테니 값이 callee 안에서 &quot;부활&quot;&lt;/b&gt;하는 셈이 돼요.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;이러면 실수로 무한 루프를 만들기 쉬워집니다.&lt;/span&gt;&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre class=&quot;swift&quot; style=&quot;background: #1e1e1e; color: #d4d4d4; padding: 16px; border-radius: 8px; overflow: auto;&quot;&gt;&lt;code&gt;struct Foo: ~Copyable {
  deinit {
    self.foo()
  }

  consuming func foo() {
    // oops, implicitly calls back into \`deinit\`
  }
}

struct Bar: ~Copyable {
  deinit {
    self.bar()
  }

  mutating func bar() {
    // oops, implicitly calls \`deinit\` on the old value of \`self\`
    // before reassigning it
    self = Bar()
  }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;이 제안은 이런 문제를 피하기 위해 &lt;b&gt;&lt;code&gt;self&lt;/code&gt;를 하나의 값으로서 mutate하거나 consume하는 걸 금지&lt;/b&gt;해요. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;대부분의 경우 이 정도 제약은 받아들일 만하다고 봅니다. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;다만 이 제약의 한 가지 결과로, &lt;code&gt;deinit&lt;/code&gt;은 같은 타입의 &lt;code&gt;mutating&lt;/code&gt;이나 &lt;code&gt;consuming&lt;/code&gt; 메서드를 호출할 수 없어요. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;그래도 &lt;code&gt;deinit&lt;/code&gt;은 필드를 다루는 &lt;code&gt;static&lt;/code&gt; 메서드를 통해 다른 메서드와 로직을 공유할 수는 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre class=&quot;swift&quot; style=&quot;background: #1e1e1e; color: #d4d4d4; padding: 16px; border-radius: 8px; overflow: auto;&quot;&gt;&lt;code&gt;struct Resource: ~Copyable {
  var resourceID: Int
  
  // Shared logic for releasing the underlying resource by ID.
  // The release operation may surface error conditions, but these can be
  // ignored in normal use.
  private static func release(resourceID: Int) throws {...}
  
  // Consuming method that releases the resource, surfacing errors to be
  // handled
  consuming func release() throws {
    try Self.release(resourceID: self.resourceID)
    discard self
  }
  
  // Deinit that implicitly closes the resource, swallowing errors
  deinit {
    do {
      try Self.release(resourceID: self.resourceID)
    } catch {
      // Ignore the error
    }
  }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;또한 &lt;code&gt;deinit&lt;/code&gt;이 값 전체의 소유권을 넘기고 싶은 상황도 있을 수 있어요. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;예를 들어 값을 정리하는 데 시간이 오래 걸린다면, &lt;code&gt;deinit&lt;/code&gt; 도중 바로 정리하기보다는 죽어가는 값을 나중에 정리하도록 큐에 넣어두는 게 나을 수 있죠. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;&lt;code&gt;deinit&lt;/code&gt;은 항상 타입의 원본 선언 안에 정의되기 때문에, 언제나 &lt;code&gt;struct&lt;/code&gt;의 레이아웃과 memberwise 이니셜라이저에 접근할 수 있어요. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;그래서 self의 필드들을 memberwise 이니셜라이저에 넘겨서 값을 명시적으로 &quot;부활&quot;시킬 수 있습니다.&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;/blockquote&gt;
&lt;pre class=&quot;swift&quot; style=&quot;background: #1e1e1e; color: #d4d4d4; padding: 16px; border-radius: 8px; overflow: auto;&quot;&gt;&lt;code&gt;let deferredCleanupValues: ConcurrentQueue

struct DeferredCleanup: ~Copyable {
  var resource1: Resource1
  var resource2: Resource2

  deinit {
    // Instead of cleaning up this value's resources immediately, push an
    // equivalent value into the queue to be cleaned up later
    let newSelf = Self(resource1: self.resource1, resource2: self.resource2)
    deferredCleanupValues.push(newSelf)
  }

  consuming func runTimeConsumingCleanup() async { ... }
}

func runDeferredCleanups() async {
  while let value = deferredCleanupValues.pop() {
    await value.runTimeConsumingCleanup()
  }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;그 밖의 제약&lt;/span&gt;&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;&lt;code&gt;deinit&lt;/code&gt; 도중 클로저 안에서 &lt;code&gt;self&lt;/code&gt;를 캡처하는 건 여전히 허용되지 않아요.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;부분적으로 consume된 self의 정리&lt;/span&gt;&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;&lt;code&gt;deinit&lt;/code&gt;이 리턴하는 시점에 &lt;code&gt;self&lt;/code&gt;의 어떤 구성 요소가 아직 consume되지 않았다면, 남은 구성 요소들은 암묵적으로 파괴돼요. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;여기엔 noncopyable 구성 요소의 &lt;code&gt;deinit&lt;/code&gt;을 실행하는 것도 포함됩니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 style=&quot;border-left: 4px solid #3a8c28; padding-left: 12px; margin-top: 32px;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;Alternatives Considered&lt;/span&gt;&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;&lt;code&gt;self&lt;/code&gt;를 전체 값으로서 mutate하거나 consume하는 제약이 실제로 너무 부담스럽다고 판명되면, &lt;b&gt;이 제약을 완화하는 방향도 열려 있어요.&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;resurrection 위험을 완화할 다른 방법들도 있습니다.&lt;/span&gt;&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;resurrect self 연산 도입하기&lt;/span&gt;&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;이 제안의 &lt;code&gt;deinit&lt;/code&gt;들은 필드로부터 memberwise-initialize해서 &lt;code&gt;self&lt;/code&gt;를 수동으로 &quot;부활&quot;시킬 수 있지만, 이건 장황해요. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;이게 흔한 패턴이 되면 이를 위한 축약 문법을 도입할 수도 있어요. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;이건 &lt;code&gt;discard self&lt;/code&gt;의 반대로 볼 수 있는데, &lt;code&gt;discard self&lt;/code&gt;가 &lt;code&gt;self&lt;/code&gt;의 암묵적 &lt;code&gt;deinit&lt;/code&gt;을 비활성화하고 &lt;code&gt;self&lt;/code&gt;를 전체 값으로 더 이상 쓸 수 없게 만드는 거라면, 이건 반대로 &lt;code&gt;self&lt;/code&gt;의 암묵적 &lt;code&gt;deinit&lt;/code&gt;을 다시 활성화해서 전체 값으로 다시 다룰 수 있게 하는 셈이니까요.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;&quot;deinit-safe&quot; 메서드에 어노테이션 달기&lt;/span&gt;&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;&lt;code&gt;deinit&lt;/code&gt;이 전체 값에 적용할 수 있는 연산을, 어떤 방식으로든 &quot;deinit-safe&quot;임을 명시적으로 표시한 메서드로만 제한할 수도 있어요. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;그렇게 표시된 &lt;code&gt;consuming&lt;/code&gt; 메서드는 반드시 &lt;code&gt;discard self&lt;/code&gt;를 하도록 요구하고, 표시된 &lt;code&gt;mutating&lt;/code&gt; 메서드는 &lt;code&gt;self&lt;/code&gt;를 완전히 재할당하는 걸 막는 식입니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;deinit이 지역적으로 정의된 메서드만 호출하도록 제한하기&lt;/span&gt;&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;명시적인 어노테이션 대신, &lt;code&gt;deinit&lt;/code&gt;이 &lt;code&gt;self&lt;/code&gt;를 mutate하거나 consume할 수 있는 방법을, &lt;code&gt;deinit&lt;/code&gt;과 함께 원본 타입 정의 안에 정의된 메서드나 같은 모듈 안의 메서드로만 제한할 수도 있어요. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;그러면 파일/모듈 단위 분석으로 &lt;code&gt;deinit&lt;/code&gt;에서 호출되는 메서드가 잠재적으로 다시 &lt;code&gt;deinit&lt;/code&gt;을 호출하는 지점을 감지할 수 있을 거예요.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;mutation 이후 self의 명시적 consumption이나 discard 요구하기&lt;/span&gt;&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;첫 번째 pitch 스레드에서 ellie20은 &quot;값이 mutate된 이후엔 어떤 의미에서 다른 값이다&quot;라고 지적하면서, &lt;code&gt;self&lt;/code&gt;를 전체 값으로 mutating한 이후에는 그 뒤의 값을 명시적으로 &lt;code&gt;discard&lt;/code&gt;하거나 &lt;code&gt;consume&lt;/code&gt;하도록 요구해야 한다고 주장했어요. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;그 시점의 값은 더 이상 원래 &lt;code&gt;deinit&lt;/code&gt; 대상이던 값이 아니기 때문이에요.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre class=&quot;swift&quot; style=&quot;background: #1e1e1e; color: #d4d4d4; padding: 16px; border-radius: 8px; overflow: auto;&quot;&gt;&lt;code&gt;struct A: ~Copyable {
  deinit {
    self.replace()
    // explicitly indicate that the replaced \`self\` is discarded, rather than
    // deinit-ed
    discard self
  }

  mutating func replace() { ... }
}

struct B: ~Copyable {
  deinit {
    self.replace()
    // explicitly indicate that the replaced \`self\` is consumed, causing deinit
    // to run again on the new value
    _ = consume self
  }

  mutating func replace() { ... }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 style=&quot;border-left: 4px solid #3a8c28; padding-left: 12px; margin-top: 32px;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;Conclusion&lt;/span&gt;&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;그동안 noncopyable 타입의 &lt;code&gt;deinit&lt;/code&gt;은 &lt;code&gt;self&lt;/code&gt;를 오직 borrow만 할 수 있어서, 내부 필드를 정리하는 로직을 &lt;code&gt;mutating&lt;/code&gt;/&lt;code&gt;consuming&lt;/code&gt; 메서드로 재사용하기 어려웠어요. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;이 제안 덕분에 필드 단위의 mutate/consume은 자유로워지면서도, &lt;code&gt;self&lt;/code&gt; 전체를 다루는 건 여전히 막아서 &quot;부활&quot;과 무한 재귀라는 위험한 함정은 피했다는 점이 인상적이에요. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;&lt;code&gt;static&lt;/code&gt; 메서드로 로직을 공유하거나, &lt;b&gt;memberwise 이니셜라이저로 명시적으로 부활시키는 우회로도 함께 마련해둔 균형 잡힌 제안&lt;/b&gt; 같습니다  &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 style=&quot;border-left: 4px solid #3a8c28; padding-left: 12px; margin-top: 32px;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;References&lt;/span&gt;&lt;/b&gt;&lt;/h2&gt;
&lt;figure id=&quot;og_1788151029441&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;object&quot; data-og-title=&quot;swift-evolution/proposals/0544-mutate-or-consume-in-deinit.md at main &amp;middot; swiftlang/swift-evolution&quot; data-og-description=&quot;This maintains proposals for changes and user-visible enhancements to the Swift Programming Language. - swiftlang/swift-evolution&quot; data-og-host=&quot;github.com&quot; data-og-source-url=&quot;https://github.com/swiftlang/swift-evolution/blob/main/proposals/0544-mutate-or-consume-in-deinit.md&quot; data-og-url=&quot;https://github.com/swiftlang/swift-evolution/blob/main/proposals/0544-mutate-or-consume-in-deinit.md&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/bU7qH5/dJMb9eT7Fnf/b4Dcl9ZmfEi18xsZot9Gdk/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600,https://scrap.kakaocdn.net/dn/cRQvmK/dJMb8XSotOw/w5xdqWnezbH1ky3m1L7pa1/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600&quot;&gt;&lt;a href=&quot;https://github.com/swiftlang/swift-evolution/blob/main/proposals/0544-mutate-or-consume-in-deinit.md&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://github.com/swiftlang/swift-evolution/blob/main/proposals/0544-mutate-or-consume-in-deinit.md&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/bU7qH5/dJMb9eT7Fnf/b4Dcl9ZmfEi18xsZot9Gdk/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600,https://scrap.kakaocdn.net/dn/cRQvmK/dJMb8XSotOw/w5xdqWnezbH1ky3m1L7pa1/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;swift-evolution/proposals/0544-mutate-or-consume-in-deinit.md at main &amp;middot; swiftlang/swift-evolution&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;This maintains proposals for changes and user-visible enhancements to the Swift Programming Language. - swiftlang/swift-evolution&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;github.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;</description>
      <category>Swift</category>
      <category>ios</category>
      <category>Mutation</category>
      <category>non-copyable</category>
      <category>SE-0544</category>
      <category>SWIFT</category>
      <author>GREEN.1229</author>
      <guid isPermaLink="true">https://green1229.tistory.com/635</guid>
      <comments>https://green1229.tistory.com/635#entry635comment</comments>
      <pubDate>Mon, 31 Aug 2026 13:37:48 +0900</pubDate>
    </item>
    <item>
      <title>[SE-0538] Disconnected</title>
      <link>https://green1229.tistory.com/634</link>
      <description>&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;안녕하세요. &lt;span style=&quot;color: #409d00;&quot;&gt;&lt;b&gt;그린&lt;/b&gt;&lt;/span&gt;입니다  &lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;이번 포스팅에서는 &lt;span style=&quot;background-color: #9feec3;&quot;&gt;&lt;b&gt;SE-0538 &amp;mdash; Disconnected&lt;/b&gt;&lt;/span&gt;에 대해 정리해보겠습니다  &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;daf.001.jpeg&quot; data-origin-width=&quot;400&quot; data-origin-height=&quot;400&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/boXVpZ/dJMcaikbwB3/RfjEYMeDOuUcniriMKVls0/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/boXVpZ/dJMcaikbwB3/RfjEYMeDOuUcniriMKVls0/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/boXVpZ/dJMcaikbwB3/RfjEYMeDOuUcniriMKVls0/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FboXVpZ%2FdJMcaikbwB3%2FRfjEYMeDOuUcniriMKVls0%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;400&quot; height=&quot;400&quot; data-filename=&quot;daf.001.jpeg&quot; data-origin-width=&quot;400&quot; data-origin-height=&quot;400&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h2 style=&quot;border-left: 4px solid #3a8c28; padding-left: 12px; margin-top: 32px;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;Intro&lt;/span&gt;&lt;/b&gt;&lt;/h2&gt;
&lt;div style=&quot;background: #f2f8ee; border-radius: 10px; padding: 16px 20px; margin: 16px 0;&quot;&gt;
&lt;p style=&quot;margin: 4px 0;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;&lt;b&gt;Proposal:&lt;/b&gt; SE-0538&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;margin: 4px 0;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;&lt;b&gt;Author:&lt;/b&gt; Franz Busch&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;margin: 4px 0;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;&lt;b&gt;Review Manager:&lt;/b&gt; Holly Borla&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;margin: 4px 0;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;&lt;b&gt;Status:&lt;/b&gt; Active review (July 17 - July 31, 2026)&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;margin: 4px 0;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;&lt;b&gt;Implementation:&lt;/b&gt; swiftlang/swift#89597&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;&lt;a style=&quot;color: #000000;&quot; href=&quot;https://github.com/swiftlang/swift-evolution/blob/main/proposals/0414-region-based-isolation.md&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;SE-0414&lt;/a&gt;는 control flow 기반 진단을 활용해서 non-Sendable 값을 isolation 경계 너머로 안전하게 보낼 수 있는지 판단하는 region-based isolation을 도입했어요. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;&lt;a style=&quot;color: #000000;&quot; href=&quot;https://github.com/swiftlang/swift-evolution/blob/main/proposals/0430-transferring-parameters-and-results.md&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;SE-0430&lt;/a&gt;은 함수 경계에서 disconnected region에 있어야 하는 값을 명시적으로 표시하는 &lt;code&gt;sending&lt;/code&gt; 파라미터/리턴 어노테이션을 도입했고요.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;이 제안은 값의 &lt;b&gt;disconnected 속성을 자료구조나 actor 같은 저장소를 거쳐서도 유지해주는 &lt;code&gt;Disconnected&lt;/code&gt; 타입을 도입&lt;/b&gt;해요. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;제네릭 타입이 &lt;code&gt;sending&lt;/code&gt; 이펙트를 신경 쓰지 않고도 non-Sendable 값을 isolation region 너머로 안전하게 옮길 수 있게 해줍니다  &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 style=&quot;border-left: 4px solid #3a8c28; padding-left: 12px; margin-top: 32px;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;Motivation&lt;/span&gt;&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;region-based isolation 덕분에 &lt;b&gt;값이 disconnected region에 있으면 isolation 경계를 넘어 non-Sendable 값을 전달할 수 있어요. &lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;SE-0430의 &lt;code&gt;sending&lt;/code&gt; 파라미터/리턴 어노테이션은 함수 경계에서 disconnected 값을 명시적으로 요구할 수 있게 해주지만, 저장 프로퍼티나 컬렉션 타입, 제네릭 컨테이너를 거치면 &lt;code&gt;sending&lt;/code&gt;은 유지되지 않아요.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;isolation 경계 너머로 처리할 원소를 저장하는 큐 구현을 생각해볼게요.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;가상의 UniqueDeque를 예로 들어봅니다.&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;/blockquote&gt;
&lt;pre class=&quot;swift&quot; style=&quot;background: #1e1e1e; color: #d4d4d4; padding: 16px; border-radius: 8px; overflow: auto;&quot;&gt;&lt;code&gt;struct UniqueDeque: ~Copyable {
  func append(_ element: consuming Element) { ... }
  func popFirst() -&amp;gt; Element? { ... }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;이 &lt;code&gt;UniqueDeque&lt;/code&gt;에 non-Sendable한 disconnected 값을 append하고, 나중에 pop할 때 다른 isolation region으로 보내고 싶은 경우가 있을 수 있어요  &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre class=&quot;arduino&quot; style=&quot;background: #1e1e1e; color: #d4d4d4; padding: 16px; border-radius: 8px; overflow: auto;&quot;&gt;&lt;code&gt;var deque = UniqueDeque()
deque.append(NonSendable())

guard let element = deque.popFirst() else { return }

Task {
    print(element) // Error: Element is assumed to be in the same isolation region as uniqueDeque
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;이걸 되게 하려면 &lt;code&gt;append&lt;/code&gt;에서 원소를 consume하고, &lt;code&gt;popFirst&lt;/code&gt;에서 &lt;code&gt;sending&lt;/code&gt;으로 반환해야 해요. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;하지만 그러면 non-Sendable이지만 &lt;b&gt;disconnected는 아닌&lt;/b&gt; 원소를 저장하고 싶은 다른 중요한 용례에서 이 타입이 크게 제약을 받게 됩니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;근본적인 한계는 &lt;code&gt;sending&lt;/code&gt;이 함수 경계의 속성이지 타입의 속성이 아니라는 점이에요. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;&lt;code&gt;UniqueDeque&lt;/code&gt; 같은 제네릭 타입은 저장된 원소가 disconnected 상태를 유지해야 하는지를 조건부로 제어할 수 없어요. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;&lt;code&gt;append&lt;/code&gt;와 &lt;code&gt;popFirst&lt;/code&gt;를 &lt;code&gt;sending&lt;/code&gt;으로 요구하면 결국 disconnected 값만 &lt;code&gt;UniqueDeque&lt;/code&gt;에 담을 수 있게 되는 셈입니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 style=&quot;border-left: 4px solid #3a8c28; padding-left: 12px; margin-top: 32px;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;Proposed Solution&lt;/span&gt;&lt;/b&gt;&lt;/h2&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;disconnected 값을 모델링할 수 있는 새로운 Disconnected 타입을 도입합니다.&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;/blockquote&gt;
&lt;pre class=&quot;arduino&quot; style=&quot;background: #1e1e1e; color: #d4d4d4; padding: 16px; border-radius: 8px; overflow: auto;&quot;&gt;&lt;code&gt;var deque = UniqueDeque&amp;lt;Disconnected&amp;gt;()
deque.append(Disconnected(NonSendable()))

guard var disconnected = deque.popFirst() else { return }
let element = disconnected.take()

Task {
    print(element)
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;&lt;code&gt;Disconnected&lt;/code&gt; 타입은 값을 wrap해서 disconnected region에 머물도록 보장해줘요. &lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;&lt;code&gt;take()&lt;/code&gt; 메서드는 &lt;code&gt;Disconnected&lt;/code&gt; wrapper를 consume하고 값을 &lt;code&gt;sending&lt;/code&gt;으로 반환해서 isolation 경계를 넘을 수 있게 해줍니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 style=&quot;border-left: 4px solid #3a8c28; padding-left: 12px; margin-top: 32px;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;Detailed Design&lt;/span&gt;&lt;/b&gt;&lt;/h2&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;Disconnected 타입은 타입 시스템을 통해 region isolation을 강제하는 wrapper예요.&lt;/span&gt;&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;Disconnected 타입 정의&lt;/span&gt;&lt;/b&gt;&lt;/h3&gt;
&lt;pre class=&quot;swift&quot; style=&quot;background: #1e1e1e; color: #d4d4d4; padding: 16px; border-radius: 8px; overflow: auto;&quot;&gt;&lt;code&gt;@frozen
public struct Disconnected: ~Copyable, Sendable {
    public init(_ value: consuming sending Value)

    public consuming func take() -&amp;gt; sending Value

    @discardableResult
    public mutating func swap(
        newValue: consuming sending Value
    ) -&amp;gt; sending Value

    public mutating func withValue(
        body: (inout sending Value) throws(Failure) -&amp;gt; Return
    ) throws(Failure) -&amp;gt; Return
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;disconnected region이란?&lt;/span&gt;&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;region-based isolation은 프로그램 실행 중 어느 시점에 존재하는 값들을, 어떤 참조가 어떤 저장소에 도달하는지에 따라 isolation region으로 나눕니다. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;어떤 값의 저장소에 다른 region으로부터/다른 region으로의 참조가 전혀 도달하지 않으면, 그 값은 disconnected region에 있는 거예요. &lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;이런 값은 actor, Task, 다른 동시성 컨텍스트 등 다른 isolation region으로 옮겨도 안전한데, 옮기는 행위 자체가 데이터 레이스를 만들 수 없기 때문이에요.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;실제로 disconnected region은 보통 다음 중 하나에서 생겨요.&lt;br /&gt;&lt;/span&gt;&lt;/blockquote&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;초기화 인자 자체가 disconnected였던, 새로 생성된 값&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;다른 disconnected 컨테이너에서 막 꺼낸 값&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;함수 경계의 &lt;code&gt;sending&lt;/code&gt; 파라미터 (callee가 disconnected region으로 전달받음)&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;함수의 &lt;code&gt;sending&lt;/code&gt; 리턴 값 (caller가 disconnected region으로 전달받음)&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;disconnected 속성은 보통 &lt;code&gt;sending&lt;/code&gt; 경계에서만 추적돼요.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt; &lt;code&gt;Disconnected&amp;lt;Value&amp;gt;&lt;/code&gt;는 그렇지 않았다면 &lt;code&gt;sending&lt;/code&gt; 경계를 벗어나는 순간 region 정보를 잃어버렸을 저장 경계(제네릭 컨테이너, 저장 프로퍼티, 큐)를 거치면서도 이 속성을 유지할 수 있게 해줘요.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;연산들&lt;/span&gt;&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;값은 &lt;code&gt;init(_:)&lt;/code&gt;을 통해 wrapper 안으로 들어오는데, 이때 &lt;code&gt;sending&lt;/code&gt; 인자가 필요해요. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;값은 &lt;code&gt;take()&lt;/code&gt;나 &lt;code&gt;swap(newValue:)&lt;/code&gt;를 통해 나가는데, 둘 다 &lt;code&gt;sending Value&lt;/code&gt;를 반환합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt; &lt;code&gt;withValue(body:)&lt;/code&gt;는 wrap된 값을 &lt;code&gt;inout sending Value&lt;/code&gt;로 받는 클로저에 그 자리에서 빌려줘요.&lt;/span&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;모든 연산은 wrapper를 consume하거나, &lt;code&gt;sending&lt;/code&gt; 경계를 통해 wrap된 값을 교체하기 때문에, wrapper의 저장소로 향하는 alias가 transfer보다 오래 살아남을 수 없어요. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;이 특성 덕분에 &lt;code&gt;Value&lt;/code&gt; 자체가 &lt;code&gt;Sendable&lt;/code&gt;인지와 무관하게 &lt;code&gt;Disconnected&lt;/code&gt;가 &lt;code&gt;Sendable&lt;/code&gt;을 채택할 수 있는 겁니다.&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;isolation 경계를 넘을 수 있는 값 만들기&lt;/span&gt;&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;&lt;code&gt;take()&lt;/code&gt;로 wrap된 값을 꺼낼 수 있어요. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;이 호출은 wrapper를 consume해서, 그 이후로는 wrapper에 어떤 연산도 할 수 없습니다. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;반환된 값은 disconnected region에 있어서, 같은 표현식 안에서 바로 isolation 경계를 넘어 전달하거나 저장해뒀다가 나중에 전달할 수 있어요.&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;pgsql&quot; style=&quot;background: #1e1e1e; color: #d4d4d4; padding: 16px; border-radius: 8px; overflow: auto;&quot;&gt;&lt;code&gt;final class Resource: ~Sendable {}

// wrapper는 Disconnected 값을 담고 있던 큐 등에서 꺼낸 것이라,
// 그 안의 resource는 이미 주변 컨텍스트와 disconnected된 것으로 알려져 있어요.
func process(wrapper: consuming Disconnected) async {
    let resource = wrapper.take()
    await Task.detached {
        use(resource) // OK: 'resource'는 disconnected region에 있음
    }.value
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;결과에 disconnected 보장이 없었다면, 캡처된 &lt;code&gt;resource&lt;/code&gt;는 caller의 region에 속한 것으로 간주되어 detached task에서의 캡처가 허용되지 않았을 거예요.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;wrap된 값을 제자리에서 교체하기&lt;/span&gt;&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;&lt;code&gt;swap(newValue:)&lt;/code&gt;로 한 번에 값을 새 값으로 교체할 수 있어요. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;&lt;code&gt;newValue&lt;/code&gt; 인자는 disconnected region에 있어야 하고, &lt;code&gt;swap&lt;/code&gt;은 이전에 저장돼 있던 값을 반환하는데 이 값도 disconnected region에 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;pgsql&quot; style=&quot;background: #1e1e1e; color: #d4d4d4; padding: 16px; border-radius: 8px; overflow: auto;&quot;&gt;&lt;code&gt;final class Resource: ~Sendable {}

func swapResources(in wrapper: inout Disconnected) async {
    let old = wrapper.swap(newValue: Resource())
    await Task.detached {
        dispose(old) // OK: 'old'는 disconnected region에 있음
    }.value
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;swap의 양방향 모두 disconnected-region 경계를 넘나들어요. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;새 값은 들어갈 때 disconnected여야 하고, 예전 값은 나올 때 disconnected로 알려집니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;꺼내지 않고 wrap된 값 mutate하기&lt;/span&gt;&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;값을 꺼내지 않고 임시로 mutable 접근이 필요하면 &lt;code&gt;withValue(body:)&lt;/code&gt;를 쓰면 돼요. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;클로저는 값을 &lt;code&gt;inout sending Value&lt;/code&gt;로 전달받고, &lt;code&gt;withValue&lt;/code&gt;는 &lt;code&gt;body&lt;/code&gt;가 반환한 값을 그대로 반환합니다.&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;pgsql&quot; style=&quot;background: #1e1e1e; color: #d4d4d4; padding: 16px; border-radius: 8px; overflow: auto;&quot;&gt;&lt;code&gt;var wrapper = Disconnected([Int]())
wrapper.withValue { array in
    array.append(42)
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;&lt;code&gt;inout sending&lt;/code&gt; 파라미터 형태는 보통의 &lt;code&gt;inout&lt;/code&gt;보다 더 많은 것을 의미해요. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;클로저 안에서는 값을 다른 isolation region으로 옮길 수 있는데, 단 클로저가 반환될 때 wrapper에는 disconnected 값이 남아 있어야 합니다. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;보통은 클로저가 제자리 mutation을 수행하지만, 이 더 관대한 형태 덕분에 &lt;code&gt;withValue&lt;/code&gt;는 값을 다른 isolation region으로 보내고 싶어하는 코드와도 조합될 수 있어요.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;init(_:)&lt;/span&gt;&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;주어진 값을 감싸는 disconnected wrapper를 만들어요. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;이 인자는 호출 시점에 disconnected region에 있어야 하는데, alias가 없는 새로 생성된 값이 이 요구사항을 바로 만족시킵니다.&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;pgsql&quot; style=&quot;background: #1e1e1e; color: #d4d4d4; padding: 16px; border-radius: 8px; overflow: auto;&quot;&gt;&lt;code&gt;final class Resource: ~Sendable {}
let wrapper = Disconnected(Resource())&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;Sendable 채택과 exclusivity&lt;/span&gt;&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;&lt;code&gt;Disconnected&lt;/code&gt; 타입은 wrap된 값이 disconnected region에 있음을 보장하기 때문에 &lt;code&gt;Sendable&lt;/code&gt;을 채택해요. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;disconnected region은 isolation 경계를 안전하게 넘을 수 있기 때문에, &lt;code&gt;T&lt;/code&gt;가 &lt;code&gt;Sendable&lt;/code&gt;인지와 무관하게 &lt;code&gt;Disconnected&amp;lt;T&amp;gt;&lt;/code&gt;를 공유하는 게 안전합니다. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;더불어 &lt;code&gt;Disconnected&lt;/code&gt;의 모든 메서드는 &lt;code&gt;consuming&lt;/code&gt;이거나 &lt;code&gt;mutating&lt;/code&gt;이라서, 컴파일러가 정적/동적 exclusivity 검사를 강제해서 겹치거나 동시적인 접근을 금지해요.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;이 API는 의도적으로 &lt;code&gt;sending&lt;/code&gt; 경계에서의 atomic transfer로만 제한돼요. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;&lt;code&gt;init&lt;/code&gt;은 &lt;code&gt;sending&lt;/code&gt; 값을 consume하고, &lt;code&gt;take&lt;/code&gt;는 wrapper를 consume해서 &lt;code&gt;sending&lt;/code&gt; 값을 반환하고, &lt;code&gt;swap&lt;/code&gt;은 wrap된 값을 다른 &lt;code&gt;sending&lt;/code&gt; 값과 교환하고, &lt;code&gt;withValue&lt;/code&gt;는 클로저가 끝날 때 disconnected 값을 남겨야 하는 조건으로 wrap된 값을 &lt;code&gt;inout sending&lt;/code&gt;으로 빌려줘요. &lt;/span&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;wrap된 값을 consume하거나 교체하지 않고 노출하는 accessor는 없습니다. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;왜 borrow accessor가 무조건적인 &lt;code&gt;Sendable&lt;/code&gt; 채택과 함께라면 안전하지 않은지는 Alternatives Considered 섹션에서 다룹니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;&lt;code&gt;Disconnected&lt;/code&gt;는 &lt;code&gt;Mutex&lt;/code&gt;, &lt;code&gt;Atomic&lt;/code&gt; 등 표준 라이브러리가 제공하는 isolation 경계를 넘기 위한 다른 primitive들과 함께 &lt;code&gt;Synchronization&lt;/code&gt; 모듈에 자리합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 style=&quot;border-left: 4px solid #3a8c28; padding-left: 12px; margin-top: 32px;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;Conclusion&lt;/span&gt;&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;&lt;code&gt;Disconnected&lt;/code&gt;는 &lt;code&gt;sending&lt;/code&gt;이 함수 경계에만 머물던 정보를 저장소를 통과해서도 유지할 수 있게 해줘요.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt; non-Sendable 값을 담는 제네릭 컨테이너나 큐를 만들 때, 그 원소가 disconnected인지 아닌지를 타입 하나로 명확히 구분할 수 있게 된 셈이죠. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;&lt;code&gt;init&lt;/code&gt;/&lt;code&gt;take&lt;/code&gt;/&lt;code&gt;swap&lt;/code&gt;/&lt;code&gt;withValue&lt;/code&gt; 모두 &lt;code&gt;sending&lt;/code&gt; 경계에서의 atomic transfer로만 제한된 설계 덕분에, 무조건적인 &lt;code&gt;Sendable&lt;/code&gt; 채택에도 안전성이 깨지지 않는다는 점이 인상적입니다  &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 style=&quot;border-left: 4px solid #3a8c28; padding-left: 12px; margin-top: 32px;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;References&lt;/span&gt;&lt;/b&gt;&lt;/h2&gt;
&lt;figure id=&quot;og_1787290188122&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;object&quot; data-og-title=&quot;swift-evolution/proposals/0538-disconnected.md at main &amp;middot; swiftlang/swift-evolution&quot; data-og-description=&quot;This maintains proposals for changes and user-visible enhancements to the Swift Programming Language. - swiftlang/swift-evolution&quot; data-og-host=&quot;github.com&quot; data-og-source-url=&quot;https://github.com/swiftlang/swift-evolution/blob/main/proposals/0538-disconnected.md&quot; data-og-url=&quot;https://github.com/swiftlang/swift-evolution/blob/main/proposals/0538-disconnected.md&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/bXQJAN/dJMb8SpZkr9/h4EYGPXkYIWw7gjtG0l3e1/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600,https://scrap.kakaocdn.net/dn/b1kbFB/dJMb9cBYUsT/KzjB2j1cFKL9caKgqLdDCk/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600&quot;&gt;&lt;a href=&quot;https://github.com/swiftlang/swift-evolution/blob/main/proposals/0538-disconnected.md&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://github.com/swiftlang/swift-evolution/blob/main/proposals/0538-disconnected.md&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/bXQJAN/dJMb8SpZkr9/h4EYGPXkYIWw7gjtG0l3e1/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600,https://scrap.kakaocdn.net/dn/b1kbFB/dJMb9cBYUsT/KzjB2j1cFKL9caKgqLdDCk/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;swift-evolution/proposals/0538-disconnected.md at main &amp;middot; swiftlang/swift-evolution&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;This maintains proposals for changes and user-visible enhancements to the Swift Programming Language. - swiftlang/swift-evolution&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;github.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;</description>
      <category>Swift</category>
      <author>GREEN.1229</author>
      <guid isPermaLink="true">https://green1229.tistory.com/634</guid>
      <comments>https://green1229.tistory.com/634#entry634comment</comments>
      <pubDate>Sat, 22 Aug 2026 08:38:31 +0900</pubDate>
    </item>
    <item>
      <title>[SE-0537] Section Placement Control for Functions</title>
      <link>https://green1229.tistory.com/633</link>
      <description>&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;안녕하세요. &lt;span style=&quot;color: #409d00;&quot;&gt;&lt;b&gt;그린&lt;/b&gt;&lt;/span&gt;입니다  &lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;이번 포스팅에서는 &lt;span style=&quot;background-color: #9feec3;&quot;&gt;&lt;b&gt;SE-0537 &amp;mdash; 함수를 위한 섹션 배치 제어&lt;/b&gt;&lt;/span&gt;에 대해 정리해보겠습니다  &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;123123.001.jpeg&quot; data-origin-width=&quot;400&quot; data-origin-height=&quot;400&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/WnegN/dJMcajwz1YG/GBpQrSQ9jJNtfQdt5UKAek/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/WnegN/dJMcajwz1YG/GBpQrSQ9jJNtfQdt5UKAek/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/WnegN/dJMcajwz1YG/GBpQrSQ9jJNtfQdt5UKAek/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FWnegN%2FdJMcajwz1YG%2FGBpQrSQ9jJNtfQdt5UKAek%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;400&quot; height=&quot;400&quot; data-filename=&quot;123123.001.jpeg&quot; data-origin-width=&quot;400&quot; data-origin-height=&quot;400&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h2 style=&quot;border-left: 4px solid #3a8c28; padding-left: 12px; margin-top: 32px;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;Intro&lt;/span&gt;&lt;/b&gt;&lt;/h2&gt;
&lt;div style=&quot;background: #f2f8ee; border-radius: 10px; padding: 16px 20px; margin: 16px 0;&quot;&gt;
&lt;p style=&quot;margin: 4px 0;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;&lt;b&gt;Proposal:&lt;/b&gt; SE-0537&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;margin: 4px 0;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;&lt;b&gt;Author:&lt;/b&gt; Doug Gregor&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;margin: 4px 0;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;&lt;b&gt;Review Manager:&lt;/b&gt; Becca Royal-Gordon&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;margin: 4px 0;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;&lt;b&gt;Status:&lt;/b&gt; Accepted&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;margin: 4px 0;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;&lt;b&gt;Implementation:&lt;/b&gt; swiftlang/swift#89740&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;&lt;a style=&quot;color: #000000;&quot; href=&quot;https://github.com/swiftlang/swift-evolution/blob/main/proposals/0492-section-control.md&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;SE-0492&lt;/a&gt;에서 도입된 &lt;code&gt;@section&lt;/code&gt; 어트리뷰트를 함수에도 붙일 수 있도록 확장하는 제안이에요. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;임베디드 시스템에서 펌웨어 부팅 코드처럼 바이너리의 특정 섹션에 들어가야 하는 코드가 있을 때 유용합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 style=&quot;border-left: 4px solid #3a8c28; padding-left: 12px; margin-top: 32px;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;Motivation&lt;/span&gt;&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;&lt;b&gt;&lt;code&gt;@section&lt;/code&gt; 어트리뷰트는 특정 엔티티가 오브젝트 파일의 어느 섹션에 배치될지 지정&lt;/b&gt;해요. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;특히 임베디드 환경에서는 링커나 다른 도구들이 특정 종류의 심볼이 특정 섹션에 있길 기대하는 경우가 많죠. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;S&lt;/span&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;E-0492는 전역/static 변수에 대한 &lt;code&gt;@section&lt;/code&gt; 지원을 도입했지만, 함수는 future direction으로 남겨뒀어요.&lt;/span&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;하지만 함수에도 이 지원이 필요합니다.&lt;/span&gt;&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;대표적인 사례가 펌웨어 진입점이나 부팅 스킴인데, startup 코드가 미리 정의된 섹션에 있어야 하는 경우가 많거든요.&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;autoit&quot; style=&quot;background: #1e1e1e; color: #d4d4d4; padding: 16px; border-radius: 8px; overflow: auto;&quot;&gt;&lt;code&gt;// 이 함수의 코드는 커스텀 섹션에 배치됩니다
@section(&quot;__TEXT,boot&quot;)
func firmwareBootEntrypoint() { ... }&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;이건 SE-0492의 &lt;a style=&quot;color: #000000;&quot; href=&quot;https://github.com/swiftlang/swift-evolution/blob/main/proposals/0492-section-control.md#section-placement-for-functions&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Future Directions에서도 이미 언급&lt;/a&gt;됐던 내용이에요.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 style=&quot;border-left: 4px solid #3a8c28; padding-left: 12px; margin-top: 32px;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;Proposed Solution&lt;/span&gt;&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;일반 함수(&lt;code&gt;func&lt;/code&gt;), 이니셜라이저(&lt;code&gt;init&lt;/code&gt;), deinitializer(&lt;code&gt;deinit&lt;/code&gt;), 클로저, accessor(&lt;code&gt;get&lt;/code&gt;, &lt;code&gt;set&lt;/code&gt; 등)를 포함한 &lt;b&gt;모든 종류의 함수에 &lt;code&gt;@section&lt;/code&gt; 어트리뷰트를 쓸 수 있게 합니다. &lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;그리고 어떤 추론 규칙이든 무시하고 플랫폼 기본 섹션을 적용하는 &lt;code&gt;@section(default)&lt;/code&gt; 표기법도 함께 도입해요.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 style=&quot;border-left: 4px solid #3a8c28; padding-left: 12px; margin-top: 32px;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;Detailed Design&lt;/span&gt;&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;&lt;code&gt;@section&lt;/code&gt; 어트리뷰트는 어떤 종류의 함수에도 적용할 수 있어요. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;문법을 보여주는 몇 가지 예시입니다.&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;/blockquote&gt;
&lt;pre class=&quot;less&quot; style=&quot;background: #1e1e1e; color: #d4d4d4; padding: 16px; border-radius: 8px; overflow: auto;&quot;&gt;&lt;code&gt;@section(&quot;__TEXT,boot&quot;)
func firmwareBootEntrypoint() { ... }

struct MyBootConfig: ~Copyable {
  @section(&quot;__TEXT,boot&quot;) init() { 
    registerCallback { @section(&quot;__TEXT,boot&quot;) in 
      ...
    }
  }

  @section(&quot;__TEXT,boot&quot;) deinit { }

  var bootPhase: Int {
    @section(&quot;__TEXT,boot&quot;) get { ... }
    @section(&quot;__TEXT,boot&quot;) set { ... } 
  }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;변수에 붙이는 &lt;code&gt;@section&lt;/code&gt;과 달리, 제네릭 함수나 제네릭 컨텍스트 안의 함수에 쓰는 데는 아무런 제약이 없어요. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;모든 함수는 결국 text 섹션에 들어가기 때문이에요.&lt;/span&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;그래서 &lt;code&gt;@section&lt;/code&gt;은 타입의 인스턴스 함수에도 적용할 수 있습니다.&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;&lt;code&gt;@section&lt;/code&gt; 어트리뷰트는 그 함수뿐 아니라 구현이 함께 만들어내는 관련 함수들에도 적용돼요. &lt;/span&gt;&lt;/b&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;예를 들어 &lt;code&gt;async&lt;/code&gt; 함수에 붙이면, 구현이 생성하는 각각의 partial function들도 이 &lt;code&gt;@section&lt;/code&gt;을 따릅니다. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;마찬가지로 제네릭 함수에 &lt;code&gt;@section&lt;/code&gt;을 붙이면, 컴파일러가 만들어내는 그 제네릭 함수의 모든 specialization에도, 그리고 원본 제네릭 정의에도 적용돼요. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;마지막으로 &lt;b&gt;&lt;code&gt;@main&lt;/code&gt; 타입의 &lt;code&gt;main&lt;/code&gt; 함수에 &lt;code&gt;@section&lt;/code&gt;이 있으면, 컴파일러가 만들어내는 실제 &lt;code&gt;main&lt;/code&gt; 진입점에도 같은 섹션이 쓰입니다.&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;accessor, closure, 지역 함수에서의 @section 추론&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;accessor나 closure에 &lt;code&gt;@section&lt;/code&gt;을 명시하지 않으면 다음 규칙으로 추론될 수 있어요.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;클로저나 지역 함수는 (있다면) 감싸고 있는 함수로부터 &lt;code&gt;@section&lt;/code&gt;을 추론합니다.&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;autoit&quot; style=&quot;background: #1e1e1e; color: #d4d4d4; padding: 16px; border-radius: 8px; overflow: auto;&quot;&gt;&lt;code&gt;@section(&quot;__TEXT,boot&quot;)
func firmwareBootEntrypoint() {
  func helper() { // @section(&quot;__TEXT,boot&quot;) 추론됨

  }

  registerCallback { // @section(&quot;__TEXT,boot&quot;) 추론됨
    ...
  }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;구현이 합성하는 읽기 전용 접근자(&lt;code&gt;get&lt;/code&gt;, &lt;code&gt;borrow&lt;/code&gt;, &lt;code&gt;yielding borrow&lt;/code&gt; 등)는, 명시적으로 작성된 다른 접근자로부터 &lt;code&gt;@section&lt;/code&gt;을 추론합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;구현이 합성하는 읽기/쓰기 또는 쓰기 접근자(&lt;code&gt;set&lt;/code&gt;, &lt;code&gt;mutate&lt;/code&gt;, &lt;code&gt;yielding mutate&lt;/code&gt;, &lt;code&gt;init&lt;/code&gt;, &lt;code&gt;didSet&lt;/code&gt;, &lt;code&gt;willSet&lt;/code&gt;)도, 명시적으로 작성된 다른 접근자로부터 &lt;code&gt;@section&lt;/code&gt;을 추론합니다. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;예를 들면 이렇게요.&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;/blockquote&gt;
&lt;pre class=&quot;less&quot; style=&quot;background: #1e1e1e; color: #d4d4d4; padding: 16px; border-radius: 8px; overflow: auto;&quot;&gt;&lt;code&gt;  var scratchSpace: MutableSpan {
    @section(&quot;__TEXT,boot&quot;) borrow { ... }
    // 합성된 &quot;get&quot;이 'borrow'로부터 @section(&quot;__TEXT,boot&quot;)를 추론함
    
    @section(&quot;__TEXT,boot&quot;) mutate { ... }
    // 합성된 &quot;set&quot;이 'mutate'로부터 @section(&quot;__TEXT,boot&quot;)를 추론함 
  }&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;border-left: 4px solid #3a8c28; background: #f2f8ee; padding: 8px 16px; margin: 16px 0;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;변수에서 그 accessor로는 &lt;code&gt;@section&lt;/code&gt;이 추론되지 않아요. &lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;border-left: 4px solid #3a8c28; background: #f2f8ee; padding: 8px 16px; margin: 16px 0;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;코드와 데이터는 보통 서로 다른 섹션에 들어가기 때문이에요. &lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;border-left: 4px solid #3a8c28; background: #f2f8ee; padding: 8px 16px; margin: 16px 0;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;local 타입(과 그 멤버)도 섹션이 추론되지 않습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;@section 추론 억제하기&lt;/span&gt;&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;&lt;code&gt;default&lt;/code&gt; 키워드를 섹션 값으로 쓰면, 이 선언에는 플랫폼에 맞는 기본 섹션을 쓰라는 뜻이 돼요. &lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;그러면 원래 적용됐을 추론 규칙을 모두 무시합니다.&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;autoit&quot; style=&quot;background: #1e1e1e; color: #d4d4d4; padding: 16px; border-radius: 8px; overflow: auto;&quot;&gt;&lt;code&gt;@section(&quot;__TEXT,boot&quot;)
func firmwareBootEntrypoint() {
  @section(default) func helper() { // @section(&quot;__TEXT,boot&quot;) 추론을 억제함

  }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;didSet/willSet 제약 완화&lt;/span&gt;&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;SE-0492는 &lt;code&gt;@section&lt;/code&gt;이 붙은 변수에 다음 제약을 뒀었어요.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;그 변수는 프로퍼티 옵저버(didSet, willSet)를 가질 수 없다.&lt;/span&gt;&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;이 제약은 불필요한 것으로 판단되어 이번 제안에서 없앱니다. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;&lt;code&gt;didSet&lt;/code&gt;이나 &lt;code&gt;willSet&lt;/code&gt;에도 &lt;code&gt;@section&lt;/code&gt;을 붙일 수 있고, 이 값은 구현이 실제로 합성하는 접근자(예: &lt;code&gt;set&lt;/code&gt;)에 대한 추론에 쓰입니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 style=&quot;border-left: 4px solid #3a8c28; padding-left: 12px; margin-top: 32px;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;Future Directions&lt;/span&gt;&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;데이터와 함수 섹션 어트리뷰트 분리하기&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;Swift의 일부 선언은 데이터 심볼과 함수 심볼을 동시에 내보내요. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;예를 들어 타입을 정의할 때 메타데이터 심볼(데이터)과 메타데이터 접근자 함수(함수)가 함께 생길 수 있죠. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;이 제안도 SE-0492도 타입 정의에 &lt;code&gt;@section&lt;/code&gt;을 허용하진 않지만, 만약 허용한다면 데이터용과 함수용 섹션을 따로 표현할 방법이 필요할 거예요. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;예를 들면 이런 모습일 수 있습니다.&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;/blockquote&gt;
&lt;pre class=&quot;less&quot; style=&quot;background: #1e1e1e; color: #d4d4d4; padding: 16px; border-radius: 8px; overflow: auto;&quot;&gt;&lt;code&gt;@section(data: &quot;__DATA,mysection&quot;)
@section(function: &quot;__FUNCTION,mysection&quot;)
public struct MyStruct { ... }&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;&lt;code&gt;data&lt;/code&gt;도 &lt;code&gt;function&lt;/code&gt;도 지정하지 않은 &lt;code&gt;@section&lt;/code&gt;은, 이 제안과 SE-0492가 다루는 것처럼 데이터/함수 구분이 모호하지 않은 곳에서만 적용될 거예요. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;타입 정의, extension, 프로토콜 conformance, 파일 단위 기본값처럼 데이터와 함수 심볼을 동시에 내보내는 새로운 자리들이 이 새 문법을 쓸 수 있게 될 겁니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;이 제안이 승인되는 과정에서, 추론을 억제하고 기본 섹션을 지정하는 @section(default) 기능이 새로 도입됐어요.&lt;/span&gt;&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 style=&quot;border-left: 4px solid #3a8c28; padding-left: 12px; margin-top: 32px;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;Conclusion&lt;/span&gt;&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;변수에만 적용되던 &lt;code&gt;@section&lt;/code&gt;이 이제 &lt;code&gt;func&lt;/code&gt;, &lt;code&gt;init&lt;/code&gt;, &lt;code&gt;deinit&lt;/code&gt;, 클로저, accessor까지 아우르게 됐어요  &lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;특히 감싸는 함수로부터 &lt;code&gt;@section&lt;/code&gt;이 자동으로 추론되는 규칙 덕분에, 펌웨어 부팅 코드처럼 특정 섹션에 몰아넣어야 하는 코드 전체를 일일이 어트리뷰트로 도배하지 않아도 될 것 같아요. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;임베디드 환경에서 Swift를 쓰는 개발자들에게 꽤 실용적인 도구가 하나 더 생긴 셈입니다  &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 style=&quot;border-left: 4px solid #3a8c28; padding-left: 12px; margin-top: 32px;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;References&lt;/span&gt;&lt;/b&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;&lt;/span&gt;&lt;b&gt;&lt;/b&gt;&lt;/h2&gt;
&lt;figure id=&quot;og_1786745937935&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;object&quot; data-og-title=&quot;swift-evolution/proposals/0537-function-sections.md at main &amp;middot; swiftlang/swift-evolution&quot; data-og-description=&quot;This maintains proposals for changes and user-visible enhancements to the Swift Programming Language. - swiftlang/swift-evolution&quot; data-og-host=&quot;github.com&quot; data-og-source-url=&quot;https://github.com/swiftlang/swift-evolution/blob/main/proposals/0537-function-sections.md&quot; data-og-url=&quot;https://github.com/swiftlang/swift-evolution/blob/main/proposals/0537-function-sections.md&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/bw8GeD/dJMb9efueSx/TECZqY5kb1kkkyCOiEePY0/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600,https://scrap.kakaocdn.net/dn/brCzKH/dJMb9frVzgx/biA718xCSbOGapEJmoOeP0/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600&quot;&gt;&lt;a href=&quot;https://github.com/swiftlang/swift-evolution/blob/main/proposals/0537-function-sections.md&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://github.com/swiftlang/swift-evolution/blob/main/proposals/0537-function-sections.md&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/bw8GeD/dJMb9efueSx/TECZqY5kb1kkkyCOiEePY0/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600,https://scrap.kakaocdn.net/dn/brCzKH/dJMb9frVzgx/biA718xCSbOGapEJmoOeP0/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;swift-evolution/proposals/0537-function-sections.md at main &amp;middot; swiftlang/swift-evolution&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;This maintains proposals for changes and user-visible enhancements to the Swift Programming Language. - swiftlang/swift-evolution&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;github.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;</description>
      <category>Swift</category>
      <category>@section</category>
      <category>SE-0537</category>
      <category>SWIFT</category>
      <author>GREEN.1229</author>
      <guid isPermaLink="true">https://green1229.tistory.com/633</guid>
      <comments>https://green1229.tistory.com/633#entry633comment</comments>
      <pubDate>Sat, 15 Aug 2026 07:20:04 +0900</pubDate>
    </item>
    <item>
      <title>[SE-0535] Add CLI for editing global mirrors configuration</title>
      <link>https://green1229.tistory.com/632</link>
      <description>&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;안녕하세요. &lt;b&gt;그린&lt;/b&gt;입니다  &lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;이번 포스팅에서는 &lt;span style=&quot;background-color: #9feec3;&quot;&gt;&lt;b&gt;SE-0535 &amp;mdash; 전역 mirrors 설정을 위한 CLI 추가&lt;/b&gt;&lt;/span&gt;에 대해 정리해보겠습니다  &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;123.001.jpeg&quot; data-origin-width=&quot;400&quot; data-origin-height=&quot;400&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/kzmdg/dJMcaafgnfB/JginJjfYXHUs8tNKmKUXAk/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/kzmdg/dJMcaafgnfB/JginJjfYXHUs8tNKmKUXAk/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/kzmdg/dJMcaafgnfB/JginJjfYXHUs8tNKmKUXAk/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fkzmdg%2FdJMcaafgnfB%2FJginJjfYXHUs8tNKmKUXAk%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;400&quot; height=&quot;400&quot; data-filename=&quot;123.001.jpeg&quot; data-origin-width=&quot;400&quot; data-origin-height=&quot;400&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h2 style=&quot;border-left: 4px solid #3a8c28; padding-left: 12px; margin-top: 32px;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;Intro&lt;/span&gt;&lt;/b&gt;&lt;/h2&gt;
&lt;div style=&quot;background: #f2f8ee; border-radius: 10px; padding: 16px 20px; margin: 16px 0;&quot;&gt;
&lt;p style=&quot;margin: 4px 0;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;&lt;b&gt;Proposal:&lt;/b&gt; SE-0535&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;margin: 4px 0;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;&lt;b&gt;Author:&lt;/b&gt; Samuel Murray&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;margin: 4px 0;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;&lt;b&gt;Review Manager:&lt;/b&gt; Tim Condon&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;margin: 4px 0;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;&lt;b&gt;Status:&lt;/b&gt; Accepted&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;margin: 4px 0;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;&lt;b&gt;Implementation:&lt;/b&gt; swiftlang/swift-package-manager#9950&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;SPM은 로컬(프로젝트 단위)과 공유(사용자 단위) mirrors 설정을 둘 다 지원하지만, CLI로는 로컬 설정 파일만 편집할 수 있었어요.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;이 제안은 기존 CLI에 전역 설정을 편집할 수 있는 --global 플래그를 옵션으로 추가합니다.&lt;/span&gt;&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 style=&quot;border-left: 4px solid #3a8c28; padding-left: 12px; margin-top: 32px;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;Motivation&lt;/span&gt;&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;원래 mirrors는 &lt;a style=&quot;color: #000000;&quot; href=&quot;https://github.com/swiftlang/swift-evolution/blob/main/proposals/0219-package-manager-dependency-mirroring.md&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;최초 제안&lt;/a&gt;에서 설명된 대로 프로젝트별 로컬 설정만 가능했어요. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;이후 릴리스에서 &lt;a style=&quot;color: #000000;&quot; href=&quot;https://github.com/swiftlang/swift-package-manager/pull/3670&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;전역 설정 파일 지원&lt;/a&gt;이 추가됐는데, &lt;b&gt;처음부터 로컬/전역 설정을 모두 지원해온 package registry의 디자인을 따른 거예요.&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;mirrors와 package registry의 전역 설정 파일은 특정 패키지를 항상 커스텀 URL에서 받아와야 하는 엔터프라이즈 환경에서 특히 유용해요. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;게다가 곧 추가될 &lt;a style=&quot;color: #000000;&quot; href=&quot;https://github.com/swiftlang/swift-package-manager/pull/9647&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;바이너리 타깃 미러링 지원&lt;/a&gt;으로 전역 설정의 유용함은 더 커질 예정입니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;하지만 현재는 전역 mirrors 설정을 쉽게 편집하고 확인할 방법이 없어요. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;유일한 방법은 설정 파일을 직접 만들고 손으로 편집하는 것뿐이죠. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;이걸 위한 CLI를 제공하면 이미 있는 전역 package registry 기능과 결을 맞추면서, 전역 mirrors 설정의 발견 가능성도 높일 수 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 style=&quot;border-left: 4px solid #3a8c28; padding-left: 12px; margin-top: 32px;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;Proposed Solution&lt;/span&gt;&lt;/b&gt;&lt;/h2&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;로컬 설정 파일을 다루는 기존 CLI는 다음과 같아요.&lt;/span&gt;&lt;/blockquote&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;&lt;code&gt;swift package config set-mirror&lt;/code&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;&lt;code&gt;swift package config unset-mirror&lt;/code&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;&lt;code&gt;swift package config get-mirror&lt;/code&gt;&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;이 제안은 이 명령어들 각각에 선택적인 &lt;code&gt;--global&lt;/code&gt; 플래그를 추가합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;예시&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;&lt;code&gt;https://example.com/file.json&lt;/code&gt;의 mirror를 전역으로 추가하려면:&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;dsconfig&quot; style=&quot;background: #1e1e1e; color: #d4d4d4; padding: 16px; border-radius: 8px; overflow: auto;&quot;&gt;&lt;code&gt;$ swift package config set-mirror --global --original https://example.com/file.json --mirror https://internal.com/file.json&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;그러면 &lt;code&gt;~/.swiftpm/configuration/mirrors.json&lt;/code&gt;에 아래 내용이 추가돼요. (파일이 없으면 새로 만듭니다)&lt;/span&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;json&quot; style=&quot;background: #1e1e1e; color: #d4d4d4; padding: 16px; border-radius: 8px; overflow: auto;&quot;&gt;&lt;code&gt;{
  &quot;object&quot; : [
    {
      &quot;mirror&quot; : &quot;https://internal.com/file.json&quot;,
      &quot;original&quot; : &quot;https://example.com/file.json&quot;
    }
    // ...
  ],
  &quot;version&quot; : 1
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;이 설정을 확인하려면:&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;dsconfig&quot; style=&quot;background: #1e1e1e; color: #d4d4d4; padding: 16px; border-radius: 8px; overflow: auto;&quot;&gt;&lt;code&gt;$ swift package config get-mirror --global --original https://example.com/file.json
https://internal.com/file.json&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;설정을 해제하려면:&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;tcl&quot; style=&quot;background: #1e1e1e; color: #d4d4d4; padding: 16px; border-radius: 8px; overflow: auto;&quot;&gt;&lt;code&gt;$ swift package config unset-mirror --global --original https://example.com/file.json&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;package registry용 CLI에서 아이디어를 얻어서, 이 명령어들 각각에 &lt;code&gt;--global&lt;/code&gt; 플래그를 추가하자고 제안해요. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;예를 들면 &lt;code&gt;swift package config set-mirror --global [...]&lt;/code&gt; 이렇게요. &lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;이 플래그와 함께 쓰면 명령어는 전역 설정 파일만 고려하게 됩니다. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;이 플래그를 쓰면 명령어를 어느 디렉터리에서든 실행할 수 있어요. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;반면 지금의 (플래그 없는) 명령어는 현재 디렉터리나 그 상위 디렉터리 어디에도 &lt;code&gt;Package.swift&lt;/code&gt;가 없으면 실패하죠.&lt;/span&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;&lt;/span&gt;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;현재 swift package config get-mirror의 동작은, 로컬 설정 파일이 비어 있거나 없으면 전역 설정 파일을 읽는 방식이에요. &lt;br /&gt;제안자는 이 동작을 그대로 두자고 제안합니다. &lt;br /&gt;로컬 설정이 하나라도 있으면 전역 설정을 완전히 무시하는 것보다, 로컬을 더 높은 우선순위로 두고 로컬/전역을 병합하는 게 더 합리적이라고 생각하지만, 이건 이 제안과는 다소 별개의 주제라 후속 제안으로 다루는 게 좋겠다고 봤다고 합니다!&lt;/blockquote&gt;
&lt;h2 style=&quot;border-left: 4px solid #3a8c28; padding-left: 12px; margin-top: 32px;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;Detailed Design&lt;/span&gt;&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;&lt;code&gt;--global&lt;/code&gt; 플래그와 함께 쓰는 모든 명령어는 어느 디렉터리에서든 사용할 수 있어요. &lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;즉, 현재 디렉터리(또는 그 상위 디렉터리)에 &lt;code&gt;Package.swift&lt;/code&gt; 파일이 있을 필요가 없습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;&lt;code&gt;--global&lt;/code&gt; 플래그 없이 쓰면 모든 명령어의 동작은 기존과 동일합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;set-mirror&lt;/span&gt;&lt;/b&gt;&lt;/h3&gt;
&lt;pre class=&quot;routeros&quot; style=&quot;background: #1e1e1e; color: #d4d4d4; padding: 16px; border-radius: 8px; overflow: auto;&quot;&gt;&lt;code&gt;$ swift package config set-mirror --help
OVERVIEW: Set a mirror for a dependency.

USAGE: swift package config set-mirror [--global] [--original ] [--mirror ]

OPTIONS:
  --global                Apply settings to all projects for this user.
  --original    The original url or identity.
  --mirror        The mirror url or identity.
  --version               Show the version.
  -h, -help, --help       Show help information.&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;이 명령어를 실행하면 &lt;code&gt;~/.swiftpm/configuration/mirrors.json&lt;/code&gt;에 mirror 설정을 추가하거나, 파일이 없으면 새로 만듭니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;unset-mirror&lt;/span&gt;&lt;/b&gt;&lt;/h2&gt;
&lt;pre class=&quot;routeros&quot; style=&quot;background: #1e1e1e; color: #d4d4d4; padding: 16px; border-radius: 8px; overflow: auto;&quot;&gt;&lt;code&gt;$ swift package config unset-mirror --help
OVERVIEW: Remove an existing mirror.

USAGE: swift package config unset-mirror [--original ] [--mirror ]

OPTIONS:
  --global                Apply settings to all projects for this user.
  --original    The original url or identity.
  --mirror        The mirror url or identity.
  --version               Show the version.
  -h, -help, --help       Show help information.&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;이 명령어를 실행하면 &lt;code&gt;~/.swiftpm/configuration/mirrors.json&lt;/code&gt;에서 일치하는 mirror 설정을 제거해요. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;일치하는 항목이 없거나 파일이 없으면 에러 메시지를 표시합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;get-mirror&lt;/span&gt;&lt;/b&gt;&lt;/h3&gt;
&lt;pre class=&quot;routeros&quot; style=&quot;background: #1e1e1e; color: #d4d4d4; padding: 16px; border-radius: 8px; overflow: auto;&quot;&gt;&lt;code&gt;OVERVIEW: Print mirror configuration for the given package dependency.

USAGE: swift package config get-mirror [--original ]

OPTIONS:
  --global                Only read settings applied to all projects for this user.
  --original    The original url or identity.
  --version               Show the version.
  -h, -help, --help       Show help information.&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;이 명령어를 실행하면 &lt;code&gt;~/.swiftpm/configuration/mirrors.json&lt;/code&gt;에서 일치하는 mirror 설정을 가져와요. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;일치하는 항목이 없거나 파일이 없으면 에러 메시지를 표시합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 style=&quot;border-left: 4px solid #3a8c28; padding-left: 12px; margin-top: 32px;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;Security&lt;/span&gt;&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;이 제안이 보안에 미치는 영향은 미미해요. 사용자 홈 디렉터리에 있는 파일을 수정하거나 읽는 정도입니다. mirrors의 &lt;a style=&quot;color: #000000;&quot; href=&quot;https://github.com/swiftlang/swift-evolution/blob/main/proposals/0219-package-manager-dependency-mirroring.md&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;최초 제안&lt;/a&gt;에서는 전역 설정이 &quot;예상 못한 함정&quot; 같은 순간을 만들 수 있다는 우려가 있었지만, SPM에 전역 mirrors 설정 지원이 이미 추가된 상태라 이 CLI를 추가한다고 해서 새로운 이슈가 생기진 않습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 style=&quot;border-left: 4px solid #3a8c28; padding-left: 12px; margin-top: 32px;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;Impact on Existing Packages&lt;/span&gt;&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;이 제안은 기존 패키지에 아무런 영향을 주지 않아요. 새 CLI 플래그를 추가할 뿐, 기존 동작은 전혀 바뀌지 않습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 style=&quot;border-left: 4px solid #3a8c28; padding-left: 12px; margin-top: 32px;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;Conclusion&lt;/span&gt;&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;작지만 실용적인 CLI 개선이에요. 그동안 전역 mirrors 설정을 편집하려면 &lt;code&gt;~/.swiftpm/configuration/mirrors.json&lt;/code&gt;을 직접 손으로 만지는 수밖에 없었는데, &lt;code&gt;--global&lt;/code&gt; 플래그 하나로 &lt;code&gt;set-mirror&lt;/code&gt;, &lt;code&gt;unset-mirror&lt;/code&gt;, &lt;code&gt;get-mirror&lt;/code&gt;를 어느 디렉터리에서든 쓸 수 있게 됐어요. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;엔터프라이즈 환경에서 특정 패키지를 항상 내부 URL로 받아오게 설정해두고 싶을 때, 그리고 곧 추가될 바이너리 타깃 미러링과 함께 쓰기에도 훨씬 편리해질 것 같습니다  &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 style=&quot;border-left: 4px solid #3a8c28; padding-left: 12px; margin-top: 32px;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;References&lt;/span&gt;&lt;/b&gt;&lt;/h2&gt;
&lt;figure id=&quot;og_1786189403564&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;object&quot; data-og-title=&quot;swift-evolution/proposals/0535-global-mirrors-configuration-cli.md at main &amp;middot; swiftlang/swift-evolution&quot; data-og-description=&quot;This maintains proposals for changes and user-visible enhancements to the Swift Programming Language. - swiftlang/swift-evolution&quot; data-og-host=&quot;github.com&quot; data-og-source-url=&quot;https://github.com/swiftlang/swift-evolution/blob/main/proposals/0535-global-mirrors-configuration-cli.md&quot; data-og-url=&quot;https://github.com/swiftlang/swift-evolution/blob/main/proposals/0535-global-mirrors-configuration-cli.md&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/chaC8q/dJMb8Xku60Y/CXWKyTWcewmOCqXsS7KXN1/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600,https://scrap.kakaocdn.net/dn/btxF3C/dJMb8TCpsj9/hJ1yPW3IKLQsvDu5vfSb6K/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600&quot;&gt;&lt;a href=&quot;https://github.com/swiftlang/swift-evolution/blob/main/proposals/0535-global-mirrors-configuration-cli.md&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://github.com/swiftlang/swift-evolution/blob/main/proposals/0535-global-mirrors-configuration-cli.md&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/chaC8q/dJMb8Xku60Y/CXWKyTWcewmOCqXsS7KXN1/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600,https://scrap.kakaocdn.net/dn/btxF3C/dJMb8TCpsj9/hJ1yPW3IKLQsvDu5vfSb6K/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;swift-evolution/proposals/0535-global-mirrors-configuration-cli.md at main &amp;middot; swiftlang/swift-evolution&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;This maintains proposals for changes and user-visible enhancements to the Swift Programming Language. - swiftlang/swift-evolution&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;github.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;</description>
      <category>Swift</category>
      <category>ios</category>
      <category>Mirrors</category>
      <category>SE-0535</category>
      <category>SWIFT</category>
      <author>GREEN.1229</author>
      <guid isPermaLink="true">https://green1229.tistory.com/632</guid>
      <comments>https://green1229.tistory.com/632#entry632comment</comments>
      <pubDate>Sat, 8 Aug 2026 20:44:33 +0900</pubDate>
    </item>
    <item>
      <title>[SE-0527] RigidArray &amp;amp; UniqueArray</title>
      <link>https://green1229.tistory.com/631</link>
      <description>&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;안녕하세요. &lt;span style=&quot;color: #409d00;&quot;&gt;&lt;b&gt;그린&lt;/b&gt;&lt;/span&gt;입니다  &lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;이번 포스팅에서는 &lt;span style=&quot;background-color: #9feec3;&quot;&gt;&lt;b&gt;SE-0527 &amp;mdash; RigidArray와 UniqueArray&lt;/b&gt;&lt;/span&gt;에 대해 정리해보겠습니다  &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;123123.001.jpeg&quot; data-origin-width=&quot;400&quot; data-origin-height=&quot;400&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b6TCH1/dJMcajiSpJc/xxoLjgkKDu4GPsXcmzkmh1/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b6TCH1/dJMcajiSpJc/xxoLjgkKDu4GPsXcmzkmh1/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b6TCH1/dJMcajiSpJc/xxoLjgkKDu4GPsXcmzkmh1/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb6TCH1%2FdJMcajiSpJc%2FxxoLjgkKDu4GPsXcmzkmh1%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;400&quot; height=&quot;400&quot; data-filename=&quot;123123.001.jpeg&quot; data-origin-width=&quot;400&quot; data-origin-height=&quot;400&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h2 style=&quot;border-left: 4px solid #3a8c28; padding-left: 12px; margin-top: 32px;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;Intro&lt;/span&gt;&lt;/b&gt;&lt;/h2&gt;
&lt;div style=&quot;background: #f2f8ee; border-radius: 10px; padding: 16px 20px; margin: 16px 0;&quot;&gt;
&lt;p style=&quot;margin: 4px 0;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;Proposal:&lt;/b&gt; SE-0527&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;margin: 4px 0;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;Authors:&lt;/b&gt; Karoy Lorentey, Alejandro Alonso&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;margin: 4px 0;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;Review Manager:&lt;/b&gt; Steve Canon&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;margin: 4px 0;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;Status:&lt;/b&gt; Implemented (Swift 6.4)&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;margin: 4px 0;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;Implementation:&lt;/b&gt; swiftlang/swift#87521&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;h2 style=&quot;border-left: 4px solid #3a8c28; padding-left: 12px; margin-top: 32px;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;Motivation&lt;/span&gt;&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;Swift 5.9에서 noncopyable struct/enum이 들어온 이후로 이를 지원하는 API가 하나둘 추가되어 왔습니다  &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;표준 라이브러리도 &lt;code&gt;Atomic&lt;/code&gt;, &lt;code&gt;Mutex&lt;/code&gt;, inline 저장소에 noncopyable 값을 담을 수 있는 &lt;code&gt;InlineArray&lt;/code&gt; 같은 타입을 직접 구현했죠. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;하지만 noncopyable 원소를 지원하는 크기 조절 가능한(resizable) 자료구조는 아직 없었습니다.&lt;/span&gt;&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;Swift 개발자라면 동적으로 크기가 변하는 값 목록이 필요할 때 &lt;code&gt;Array&lt;/code&gt;를 찾게 마련&lt;/b&gt;인데, 안타깝게도 클래식 &lt;code&gt;Array&lt;/code&gt;는 noncopyable 값을 지원하지 않아요. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;noncopyable 원소 지원을 Array에 억지로 끼워 넣는 방법은 두 가지가 있을 수 있어요.&lt;/span&gt;&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;1️⃣ &lt;b&gt;&lt;code&gt;Array&lt;/code&gt;를 copyable로 유지하면서, mutation 연산이 원소를 복사하는 대신 다른 방식으로 uniqueness를 보장하게 만드는 방법&lt;/b&gt;. &lt;br /&gt;예를 들어 mutation이 런타임 에러를 일으키게 하거나, 원소를 어떻게 clone할지 설명하는 새 인자를 추가하는 방식이 있는데, 둘 다 실제로는 받아들이기 힘든 프로그래밍 경험으로 이어집니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;2️⃣ &lt;b&gt;&lt;code&gt;Array&lt;/code&gt;를 원소의 copyability에 따라 조건부로 copyable하게 만드는 방법.&lt;/b&gt; &lt;br /&gt;이러려면 mutation 연산이 &lt;code&gt;Element&lt;/code&gt;가 copyable인 경우에만 copy-on-write 경로로 분기하는 런타임 조건을 추가로 가져야 해요. 여기엔 두 가지 기술적 문제가 있습니다. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;Swift 코드는 현재 런타임에 타입 인자가 copyable인지 확인할 방법이 없고, 이런 &quot;conformance&quot; 체크는 모든 배열 mutation에 잠재적 오버헤드를 더하게 됩니다.&lt;/b&gt; &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;첫 번째 문제는 해결 가능하지만, 두 번째는 굉장히 가져가기 어려운 문제예요.&lt;/span&gt;&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;특히 noncopyable 원소를 허용하는 제네릭 컨텍스트에 큰 영향을 주는데, 그런 컨텍스트에서는 copyability 체크가 런타임 조건이어야만 하거든요. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;noncopyable 원소를 허용하는 컨텍스트에서 호출됐다는 이유만으로 &lt;code&gt;append&lt;/code&gt;가 storage가 unique하다고 가정할 순 없으니까요.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;이미 복잡한 &lt;code&gt;Array&lt;/code&gt;의 성능 분석을 더 어렵게 만드는 건 noncopyable 타입 도입의 배경이 된 &lt;a href=&quot;https://github.com/swiftlang/swift/blob/main/docs/OwnershipManifesto.md&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Swift Ownership Manifesto&lt;/a&gt;의 목표에 정면으로 반하는 일이에요. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;목표는 단순히 noncopyable 값을 담는 배열이 아니라, 예측 가능하고 분석하기 쉬운 좋은 성능으로 그걸 해내는 겁니다.&lt;/span&gt;&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;이 외에도 Array에는 예측 불가능한 복잡도 급증을 만드는 두 가지 주요 원인이 있어요.&lt;/span&gt;&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;1️⃣ copy-on-write 값 시맨틱스&lt;/b&gt; &amp;mdash; 공유된 복사본을 실수로 mutate하기 쉽습니다. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;그럴 때마다 배열 전체를 새로 할당해야 해서, 평소엔 상수 복잡도인 단순 subscript 재할당 같은 연산도 선형 복잡도 괴물이 될 수 있어요.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;2️⃣ 동적 자료구조&lt;/b&gt; &amp;mdash; 필요할 때마다 암묵적으로 크기를 재조정합니다. 적&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;절한 크기의 새 버퍼를 할당하고 기존 원소를 복사하거나 옮기는 방식이라, 대부분은 상수 시간/공간에 실행되지만 어쩌다 한 번씩 resize가 트리거되면서 갑자기 선형이 돼요. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;기하급수적 성장 패턴 덕분에 &lt;code&gt;append&lt;/code&gt;는 평균적으로 amortized O(1)이지만,&lt;b&gt; 실제 최악의 경우 복잡도는 O(count)입니다.&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;이 두 특징 자체가 나쁜 건 아니에요. &lt;/span&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;오히려 Swift의 프로그래밍 모델을 크게 단순화해주는 바람직한 이점이죠. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;하지만 신뢰할 수 있는 고성능이 필요한 컨텍스트에서는 이 특징들이 코드가 런타임에 어떻게 동작할지 분석하고 보장하기 어렵게 만드는 걸림돌이 됩니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;Array에 기능을 계속 덧붙이는 건 답이 아니에요.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;필요한 건 &lt;code&gt;Array&lt;/code&gt;보다 더 예측 가능한 성능이 필요한 용례에 특화된 추가 배열 구현체입니다&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-size=&quot;size18&quot; data-ke-style=&quot;style1&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;그럼 새 배열 타입이 몇 개나 필요할까요? &lt;/span&gt;&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;위 두 특징은 기술적으로 서로 독립적이라 개별적으로 켜고 끌 수 있어요. &lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;그러면 &lt;b&gt;이론상 네 가지 조합&lt;/b&gt;이 나오는데, 그중 하나는 이미 존재하는 &lt;code&gt;Array&lt;/code&gt;입니다.&lt;/span&gt;&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%; margin: 16px 0;&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;th style=&quot;border: 1px solid #ddd; padding: 8px;&quot;&gt;&amp;nbsp;&lt;/th&gt;
&lt;th style=&quot;border: 1px solid #ddd; padding: 8px;&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;Noncopyable&lt;/span&gt;&lt;/th&gt;
&lt;th style=&quot;border: 1px solid #ddd; padding: 8px;&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;Copy-on-write&lt;/span&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;border: 1px solid #ddd; padding: 8px;&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;Fixed capacity&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;border: 1px solid #ddd; padding: 8px; text-align: center;&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;???&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;border: 1px solid #ddd; padding: 8px; text-align: center;&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;???&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;border: 1px solid #ddd; padding: 8px;&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;Dynamic&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;border: 1px solid #ddd; padding: 8px; text-align: center;&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;???&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;border: 1px solid #ddd; padding: 8px; text-align: center;&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;code&gt;Array&lt;/code&gt;&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;fixed-capacity 자료구조를 쓰는 주된 이유는 암묵적 할당을 피하기 위해서인데, copy-on-write는 그것과 정면으로 충돌해요. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;그래서 오른쪽 위 칸은 비워둘 수 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%; margin: 16px 0;&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;th style=&quot;border: 1px solid #ddd; padding: 8px;&quot;&gt;&amp;nbsp;&lt;/th&gt;
&lt;th style=&quot;border: 1px solid #ddd; padding: 8px;&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;Noncopyable&lt;/span&gt;&lt;/th&gt;
&lt;th style=&quot;border: 1px solid #ddd; padding: 8px;&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;Copy-on-write&lt;/span&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;border: 1px solid #ddd; padding: 8px;&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;Fixed capacity&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;border: 1px solid #ddd; padding: 8px; text-align: center;&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;???&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;border: 1px solid #ddd; padding: 8px; text-align: center;&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;---&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;border: 1px solid #ddd; padding: 8px;&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;Dynamic&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;border: 1px solid #ddd; padding: 8px; text-align: center;&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;???&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;border: 1px solid #ddd; padding: 8px; text-align: center;&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;code&gt;Array&lt;/code&gt;&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 style=&quot;border-left: 4px solid #3a8c28; padding-left: 12px; margin-top: 32px;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;Proposed Solution&lt;/span&gt;&lt;/b&gt;&lt;/h2&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;표준 라이브러리에 RigidArray와 UniqueArray라는 두 새 배열 타입을 추가할 것을 제안합니다.&lt;/span&gt;&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;둘 다 진짜 배열 타입으로, append, insert, replace, remove, 임의 재정렬, 정수 오프셋을 통한 빠른 접근 등 익숙한 배열 연산을 제공&lt;/b&gt;해요. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;둘 다 하나의 힙 할당된 연속 메모리 영역을 저장소로 쓰고, 부분적으로만 초기화될 수 있으며, 초기화된 항목들은 앞쪽에 모여 있어요. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;요컨대 기존 &lt;code&gt;Array&lt;/code&gt;, &lt;code&gt;ContiguousArray&lt;/code&gt;와 마찬가지로 고전적인 가변 크기 배열 자료구조를 구현합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;이 타입들은 Swift 툴체인의 새 모듈 &lt;code&gt;Containers&lt;/code&gt;에 포함돼요. s&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;wift-collections의 &lt;code&gt;Collections&lt;/code&gt;처럼, 이 모듈은 앞으로 ring buffer 같은 자료구조들의 집합이 될 예정입니다 ☺️&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;UniqueArray&lt;/span&gt;&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;code&gt;UniqueArray&lt;/code&gt;는 &lt;b&gt;copy-on-write 컨테이너를 피하고 싶지만 메모리를 엄격하게 관리할 필요는 없는, 일반적인 고성능 컨텍스트에 좋은 선택&lt;/b&gt;이에요.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;C++의 &lt;code&gt;std::vector&lt;/code&gt;나 Rust의 &lt;code&gt;Vec&lt;/code&gt;처럼 단순하고 동적으로 크기가 조정되는 배열 타입입니다.&lt;/span&gt;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;UniqueArray는 저장소가 항상 유일하게(uniquely) 소유되는 Array variant예요.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;code&gt;UniqueArray&lt;/code&gt;를 noncopyable 타입으로 선언해서 정적으로 강제하는데, 그래서 &lt;code&gt;UniqueArray&lt;/code&gt; 자신은 한 번에 하나의 변수(저장 프로퍼티, 지역 변수, 함수 인자 등)만 가질 수 있고 그 변수를 통해서만 mutate할 수 있어요. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;다른 변수로 옮길 수는 있지만, 이건 원본을 consume해서 사용 불가능/미초기화 상태로 만듭니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre class=&quot;reasonml&quot; style=&quot;background: #1e1e1e; color: #d4d4d4; padding: 16px; border-radius: 8px; overflow: auto;&quot;&gt;&lt;code&gt;import Containers

struct FileHandle: ~Copyable {
  let fd: UInt32

  init(reading path: String) throws { fd = try open(path, .read) }

  deinit {
    try! close(fd)
  }
}

let foo = try FileHandle(reading: &quot;foo.txt&quot;)
let bar = try FileHandle(reading: &quot;bar.md&quot;)

var a = UniqueArray()
a.append(foo) // OK, consumes \`foo\`
a.append(bar) // OK, consumes \`bar\`

var b = a // OK, consumes \`a\`, moving the array instance into \`b\`

b.append(try FileHandle(reading: &quot;baz.swift&quot;)) // OK
// \`b\`는 이제 foo.txt, bar.md, baz.swift에 대한 열린 핸들을 담고 있음

a.append(try FileHandle(reading: &quot;Info.plist&quot;)) // error: \`a\` used after consume (used here)&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;noncopyable 자신인 덕분에 &lt;code&gt;UniqueArray&lt;/code&gt;는 위 예시의 파일 핸들처럼 noncopyable 원소도 자연스럽게 담을 수 있어요.&lt;/b&gt; &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;원소를 다루는 배열 연산들은 소유권을 신중하게 고려해서 설계되었고, &lt;code&gt;consuming&lt;/code&gt;이나 &lt;code&gt;borrowing&lt;/code&gt; 키워드로 원소 소유권과 어떻게 상호작용하는지 표시되어 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;제대로 된 동적 크기 조정 컨테이너답게, &lt;code&gt;UniqueArray&lt;/code&gt;도 기하급수적 성장 곡선에 의존해서 (amortized) 성능을 확보해요. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;resize가 필요할 때 이전 capacity에 상수 배율을 곱하는 방식이지, 단순히 그 연산에 필요한 만큼만 선형으로 키우지 않습니다. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;이 키워지는 비율은 내부 구현 세부사항이라 환경/플랫폼/Swift 릴리스에 따라 바뀔 수 있고, 사용자가 설정할 수 없습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;RigidArray&lt;/span&gt;&lt;/b&gt;&lt;/h3&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;핵심 시스템 프로그래밍, 메모리 제약이 있는 임베디드 플랫폼, 실시간 컨텍스트 같은 가장 low-level인 용례에는 UniqueArray만으로는 충분하지 않아요.&lt;br /&gt;&lt;/span&gt;&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;고정 capacity를 갖는 noncopyable 배열 타입이 필요합니다.&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;가용 메모리가 킬로바이트 단위인 환경을 위한 Swift 코드를 작성한다고 생각해보면, 모든 할당이 소스에 명시적으로 드러나서 정확히 계산하고 예산을 세울 수 있어야 해요. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;이런 컨텍스트에서는 알아서 resize하거나 복사하는 컨테이너 타입이 들어설 자리가 없죠.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;RigidArray는 이런 용례를 위한 타입이고, 이름 그대로 유연하지 않고 rigid(경직된)한 성격을 반영합니다.&lt;/span&gt;&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;code&gt;RigidArray&lt;/code&gt; 인스턴스는 항상 특정 capacity로 할당되고, 그 안에서만 동작해야 해요. &lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;그래서 더 이상 새 항목을 담을 수 없는 &quot;가득 찬&quot; 상태가 될 수 있고, 가득 찬 &lt;code&gt;RigidArray&lt;/code&gt;에 값을 추가하려 하면 런타임 트랩이 발생합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre class=&quot;stylus&quot; style=&quot;background: #1e1e1e; color: #d4d4d4; padding: 16px; border-radius: 8px; overflow: auto;&quot;&gt;&lt;code&gt;var c = RigidArray(capacity: 2)
print(c.isFull)       // =&amp;gt; false
print(c.freeCapacity) // =&amp;gt; 2

c.append(23)
print(c.isFull)       // =&amp;gt; false
print(c.freeCapacity) // =&amp;gt; 1

c.append(42)
print(c.isFull)       // =&amp;gt; true
print(c.freeCapacity) // =&amp;gt; 0

c.append(7) // runtime error: RigidArray capacity overflow&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;이걸 복구 가능한 에러가 아니라 precondition 위반으로 다루면, &lt;b&gt;&lt;code&gt;RigidArray&lt;/code&gt;가 &lt;code&gt;UniqueArray&lt;/code&gt;와 같은 기본 연산을 제공하면서도 향후 이 둘을 &lt;a href=&quot;https://github.com/apple/swift-collections/blob/1.4.1/Sources/ContainersPreview/Protocols/Container/RangeReplaceableContainer.swift&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;ownership-aware RangeReplaceableCollection 같은 추상화&lt;/a&gt; 아래로 통합&lt;/b&gt;할 길을 열어둘 수 있어요. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;또한 연산들이 어떤 식으로든 실패를 복구 가능하게 보고하도록 억지로 복잡하게 만들 필요도 없어지고요.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;실제로 &lt;code&gt;RigidArray&lt;/code&gt; 저장소를 오버플로우시키는 건 프로그래머의 실수처럼 느껴져요. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;타입을 잘못 사용했다는 신호지, 일상적인 문제가 아닙니다. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;빈 &lt;code&gt;Array&lt;/code&gt;에서 마지막 항목을 지우려 하면 트랩이 나는 것처럼, 가득 찬 &lt;code&gt;RigidArray&lt;/code&gt;에 항목을 추가하려는 것도 자연스럽게 트랩으로 이어집니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;code&gt;RigidArray&lt;/code&gt;는 스스로 resize하지 않지만, capacity가 타입의 일부는 아니에요. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;rigid array 인스턴스는 사실 &lt;code&gt;reallocate&lt;/code&gt; 연산을 명시적으로 호출해서 임의로 저장소를 키우거나 줄일 수 있습니다.&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre class=&quot;stylus&quot; style=&quot;background: #1e1e1e; color: #d4d4d4; padding: 16px; border-radius: 8px; overflow: auto;&quot;&gt;&lt;code&gt;var d = RigidArray(capacity: 2)
d.append(10)
d.append(20)
print(d.isFull)       // =&amp;gt; true
print(d.freeCapacity) // =&amp;gt; 0

d.reallocate(capacity: 10)
print(d.isFull)       // =&amp;gt; false
print(d.freeCapacity) // =&amp;gt; 8

d.append(30) // OK!&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;배열은 요청한 만큼 정확히 저장소를 할당해요 (더 많지도 적지도 않게). &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;이 연산 덕분에 &lt;code&gt;RigidArray&lt;/code&gt;로 임의의 커스텀 resize 로직을 갖는 wrapper 배열 타입도 만들 수 있어요. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;사&lt;/span&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;실 &lt;code&gt;UniqueArray&lt;/code&gt; 자체가 그렇게 구현되어 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 style=&quot;border-left: 4px solid #3a8c28; padding-left: 12px; margin-top: 32px;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;Detailed Design&lt;/span&gt;&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;타입 선언&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;pre class=&quot;less&quot; style=&quot;background: #1e1e1e; color: #d4d4d4; padding: 16px; border-radius: 8px; overflow: auto;&quot;&gt;&lt;code&gt;@frozen
public struct RigidArray: ~Copyable {}

extension RigidArray: Sendable where Element: Sendable &amp;amp; ~Copyable {}

@frozen
public struct UniqueArray: ~Copyable {}

extension UniqueArray: Sendable where Element: Sendable &amp;amp; ~Copyable {}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;둘 다 갖는 API &amp;mdash; 기본&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;code&gt;capacity&lt;/code&gt;, &lt;code&gt;freeCapacity&lt;/code&gt;, &lt;code&gt;span&lt;/code&gt;/&lt;code&gt;mutableSpan&lt;/code&gt;, &lt;code&gt;isTriviallyIdentical(to:)&lt;/code&gt;, 그리고 &lt;code&gt;OutputSpan&lt;/code&gt;을 통해 저장소를 직접 편집하는 &lt;code&gt;edit(_:)&lt;/code&gt;, capacity를 조정하는 &lt;code&gt;reallocate(capacity:)&lt;/code&gt;와 &lt;code&gt;reserveCapacity(_:)&lt;/code&gt;가 공통으로 제공됩니다. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;copyable 원소에 대해서는 &lt;code&gt;clone()&lt;/code&gt; / &lt;code&gt;clone(capacity:)&lt;/code&gt;로 깊은 복사도 가능해요.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre class=&quot;swift&quot; style=&quot;background: #1e1e1e; color: #d4d4d4; padding: 16px; border-radius: 8px; overflow: auto;&quot;&gt;&lt;code&gt;extension [Rigid|Unique]Array where Element: ~Copyable {
  public var capacity: Int { get }
  public var freeCapacity: Int { get }
  public var span: Span { get }
  public var mutableSpan: MutableSpan { mutating get }
  public func isTriviallyIdentical(to: borrowing Self) -&amp;gt; Bool

  public mutating func edit(
    _ body: (inout OutputSpan) throws(E) -&amp;gt; R
  ) throws(E) -&amp;gt; R

  public mutating func reallocate(capacity newCapacity: Int)
  public mutating func reserveCapacity(_ n: Int)
}

extension [Rigid|Unique]Array where Element: Copyable {
  public func clone() -&amp;gt; Self
  public func clone(capacity: Int) -&amp;gt; Self
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;둘 다 갖는 API &amp;mdash; 이니셜라이저&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;pre class=&quot;swift&quot; style=&quot;background: #1e1e1e; color: #d4d4d4; padding: 16px; border-radius: 8px; overflow: auto;&quot;&gt;&lt;code&gt;extension [Rigid|Unique]Array where Element: ~Copyable {
  public init()
  public init(capacity: Int)

  public init(
    capacity: Int,
    initializingWith initializer: (inout OutputSpan) throws(E) -&amp;gt; Void
  ) throws(E)
}

extension [Rigid|Unique]Array where Element: Copyable {
  public init(repeating repeatedValue: Element, count: Int)

  public init(
    capacity: Int? = nil,
    copying span: Span
  )
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;둘 다 갖는 API &amp;mdash; 컬렉션 기반&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;배열의 위치를 나타내는 &lt;code&gt;Index&lt;/code&gt;는 정수 오프셋(&lt;code&gt;typealias Index = Int&lt;/code&gt;)이고, &lt;code&gt;isEmpty&lt;/code&gt;, &lt;code&gt;count&lt;/code&gt;, &lt;code&gt;startIndex&lt;/code&gt;, &lt;code&gt;endIndex&lt;/code&gt;, &lt;code&gt;indices&lt;/code&gt;, subscript, &lt;code&gt;swapAt&lt;/code&gt;, &lt;code&gt;index(after:)&lt;/code&gt;/&lt;code&gt;index(before:)&lt;/code&gt;, &lt;code&gt;formIndex&lt;/code&gt; 계열, &lt;code&gt;distance(from:to:)&lt;/code&gt; 등 기존 &lt;code&gt;Collection&lt;/code&gt; API와 결을 맞춘 연산들이 제공됩니다. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;성능을 위해 대부분의 인덱스 관련 연산은 인덱스 유효성을 미리 검증하지 않고, 실제로 접근할 때 검증을 미룹니다.&lt;/span&gt;&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre class=&quot;swift&quot; style=&quot;background: #1e1e1e; color: #d4d4d4; padding: 16px; border-radius: 8px; overflow: auto;&quot;&gt;&lt;code&gt;extension [Rigid|Unique]Array where Element: ~Copyable {
  public typealias Index = Int

  public var isEmpty: Bool { get }
  public var count: Int { get }
  public var startIndex: Int { get }
  public var endIndex: Int { get }
  public var indices: Range { get }

  public subscript(position: Int) -&amp;gt; Element {
    borrow
    mutate
  }

  public mutating func swapAt(_ i: Int, _ j: Int)

  public func index(after index: Int) -&amp;gt; Int
  public func index(before index: Int) -&amp;gt; Int
  public func formIndex(after index: inout Int)
  public func formIndex(before index: inout Int)
  public func index(_ index: Int, offsetBy n: Int) -&amp;gt; Int
  public func distance(from start: Index, to end: Index) -&amp;gt; Int

  public func formIndex(
    _ index: inout Index,
    offsetBy n: inout Int,
    limitedBy limit: Index
  )
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;둘 다 갖는 API &amp;mdash; Append&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;단일 원소 &lt;code&gt;append(_:)&lt;/code&gt; 외에, &lt;code&gt;OutputSpan&lt;/code&gt;을 직접 채우는 &lt;code&gt;append(addingCount:initializingWith:)&lt;/code&gt;, 버퍼나 &lt;code&gt;OutputSpan&lt;/code&gt;을 이동시키는 &lt;code&gt;append(moving:)&lt;/code&gt;, copyable 원소를 위한 버퍼/span/시퀀스 복사 &lt;code&gt;append(copying:)&lt;/code&gt; 계열이 있습니다. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;capacity가 부족하면 &lt;code&gt;RigidArray&lt;/code&gt;는 런타임 에러, &lt;code&gt;UniqueArray&lt;/code&gt;는 기하급수적으로 storage를 늘려요.&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;swift&quot; style=&quot;background: #1e1e1e; color: #d4d4d4; padding: 16px; border-radius: 8px; overflow: auto;&quot;&gt;&lt;code&gt;extension [Rigid|Unique]Array where Element: ~Copyable {
  public mutating func append(_ item: consuming Element)

  public mutating func append(
    addingCount newItemCount: Int,
    initializingWith initializer: (inout OutputSpan) throws(E) -&amp;gt; Void
  ) throws(E)

  public mutating func append(
    moving items: UnsafeMutableBufferPointer
  )

  public mutating func append(
    moving items: inout OutputSpan
  )
}

extension [Rigid|Unique]Array where Element: Copyable {
  public mutating func append(
    copying newElements: UnsafeBufferPointer
  )
  public mutating func append(
    copying newElements: UnsafeMutableBufferPointer
  )
  public mutating func append(copying newElements: Span)
  public mutating func append(copying newElements: some Sequence)
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;둘 다 갖는 API &amp;mdash; Insert&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;지정한 위치에 원소를 끼워 넣는 &lt;code&gt;insert(_:at:)&lt;/code&gt;부터, &lt;code&gt;OutputSpan&lt;/code&gt;을 채우는 버전, 버퍼/span을 이동/복사하는 버전까지 append와 짝을 이루는 형태로 제공됩니다. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;지정 위치 이후 원소들은 뒤로 밀려서 공간을 만듭니다.&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;swift&quot; style=&quot;background: #1e1e1e; color: #d4d4d4; padding: 16px; border-radius: 8px; overflow: auto;&quot;&gt;&lt;code&gt;extension [Rigid|Unique]Array where Element: ~Copyable {
  public mutating func insert(_ item: consuming Element, at index: Int)

  public mutating func insert(
    addingCount newItemCount: Int,
    at index: Int,
    initializingWith initializer: (inout OutputSpan) throws(E) -&amp;gt; Void
  ) throws(E)

  public mutating func insert(
    moving items: UnsafeMutableBufferPointer,
    at index: Int
  )

  public mutating func insert(
    moving items: inout OutputSpan,
    at index: Int
  )
}

extension [Rigid|Unique]Array where Element: Copyable {
  public mutating func insert(
    copying newElements: UnsafeBufferPointer, at index: Int
  )
  public mutating func insert(
    copying newElements: UnsafeMutableBufferPointer,
    at index: Int
  )
  public mutating func insert(
    copying newElements: Span, at index: Int
  )
  public mutating func insert(
    copying newElements: some Collection, at index: Int
  )
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;둘 다 갖는 API &amp;mdash; Remove&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;pre class=&quot;swift&quot; style=&quot;background: #1e1e1e; color: #d4d4d4; padding: 16px; border-radius: 8px; overflow: auto;&quot;&gt;&lt;code&gt;extension [Rigid|Unique]Array where Element: ~Copyable {
  public mutating func popLast() -&amp;gt; Element?
  public mutating func removeLast() -&amp;gt; Element
  public mutating func removeLast(_ k: Int)
  public mutating func remove(at index: Int) -&amp;gt; Element
  public mutating func removeSubrange(_ bounds: Range)
  public mutating func removeSubrange(_ bounds: some RangeExpression)
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;둘 다 갖는 API &amp;mdash; Replace&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;지정한 범위를 새 항목으로 교체하는 &lt;code&gt;replaceSubrange&lt;/code&gt; 계열이에요. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;r&lt;/span&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;emove 후 insert하는 것과 같은 효과지만, 원소를 두 번 옮기지 않아서 상수 배 더 빠릅니다.&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;swift&quot; style=&quot;background: #1e1e1e; color: #d4d4d4; padding: 16px; border-radius: 8px; overflow: auto;&quot;&gt;&lt;code&gt;extension [Rigid|Unique]Array where Element: ~Copyable {
  public mutating func replaceSubrange(
    _ subrange: Range,
    addingCount newItemCount: Int,
    initializingWith initializer: (inout OutputSpan) throws(E) -&amp;gt; Void
  ) throws(E) -&amp;gt; Void

  public mutating func replaceSubrange(
    _ subrange: Range,
    moving newElements: UnsafeMutableBufferPointer
  )

  public mutating func replaceSubrange(
    _ subrange: Range,
    moving items: inout OutputSpan
  )
}

extension [Rigid|Unique]Array where Element: Copyable {
  public mutating func replaceSubrange(
    _ subrange: Range,
    copying newElements: UnsafeBufferPointer
  )
  public mutating func replaceSubrange(
    _ subrange: Range,
    copying newElements: UnsafeMutableBufferPointer
  )
  public mutating func replaceSubrange(
    _ subrange: Range,
    copying newElements: Span
  )
  public mutating func replaceSubrange(
    _ subrange: Range,
    copying newElements: consuming some Collection
  )
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;둘 다 갖는 API &amp;mdash; Conformance&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;두 타입 모두 &lt;code&gt;Equatable&lt;/code&gt;, &lt;code&gt;Hashable&lt;/code&gt;, &lt;code&gt;CustomStringConvertible&lt;/code&gt;, &lt;code&gt;CustomDebugStringConvertible&lt;/code&gt;을 채택하고, &lt;a href=&quot;https://github.com/swiftlang/swift-evolution/blob/main/proposals/0516-borrowing-sequence.md&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;SE-0516&lt;/a&gt;에서 제안된 &lt;code&gt;BorrowingSequence&lt;/code&gt;도 채택해서 그 프로포절의 &lt;code&gt;SpanIterator&lt;/code&gt;를 iterator로 씁니다.&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;swift&quot; style=&quot;background: #1e1e1e; color: #d4d4d4; padding: 16px; border-radius: 8px; overflow: auto;&quot;&gt;&lt;code&gt;extension [Rigid|Unique]Array: Equatable where Element: Equatable &amp;amp; ~Copyable {
  public static func ==(left: borrowing Self, right: borrowing Self) -&amp;gt; Bool
}

extension [Rigid|Unique]Array: Hashable where Element: Hashable &amp;amp; ~Copyable {
  public func hash(into hasher: inout Hasher)
}

extension [Rigid|Unique]Array: CustomStringConvertible where Element: ~Copyable {
  public var description: String { get }
}

extension [Rigid|Unique]Array: CustomDebugStringConvertible where Element: ~Copyable {
  public var debugDescription: String { get }
}

extension [Rigid|Unique]Array: BorrowingSequence where Element: ~Copyable {
  @lifetime(borrow self)
  public func makeBorrowingIterator() -&amp;gt; SpanIterator
}&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;border-left: 4px solid #3a8c28; background: #f2f8ee; padding: 8px 16px; margin: 16px 0;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;code&gt;CustomStringConvertible&lt;/code&gt;과 &lt;code&gt;CustomDebugStringConvertible&lt;/code&gt; 채택은 &lt;a href=&quot;https://github.com/swiftlang/swift-evolution/blob/main/proposals/0499-support-non-copyable-simple-protocols.md&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;SE-0499&lt;/a&gt;가 구현된 뒤에야 정식으로 배포될 수 있어요. &lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;border-left: 4px solid #3a8c28; background: #f2f8ee; padding: 8px 16px; margin: 16px 0;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;그 전까지는 (지금으로선 다소 소박한) &lt;code&gt;description&lt;/code&gt;/&lt;code&gt;debugDescription&lt;/code&gt; 구현을 우선 제공합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;RigidArray 전용 API&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;code&gt;isFull&lt;/code&gt; 프로퍼티, 시퀀스/컬렉션을 복사해서 초기화하는 이니셜라이저, capacity가 부족하면 항목을 그대로 돌려주는 &lt;code&gt;pushLast(_:)&lt;/code&gt;, 저장 capacity는 유지한 채 모든 원소를 지우는 &lt;code&gt;removeAll()&lt;/code&gt;이 있어요.&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;swift&quot; style=&quot;background: #1e1e1e; color: #d4d4d4; padding: 16px; border-radius: 8px; overflow: auto;&quot;&gt;&lt;code&gt;extension RigidArray where Element: ~Copyable {
  public var isFull: Bool { get }

  public init(
    capacity: Int,
    copying contents: some Sequence
  )

  public init(
    capacity: Int? = nil,
    copying contents: some Collection
  )

  public mutating func pushLast(_ item: consuming Element) -&amp;gt; Element?

  public mutating func removeAll()
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;UniqueArray 전용 API&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;초기 capacity를 지정하는 이니셜라이저와, capacity를 유지할지 선택할 수 있는 &lt;code&gt;removeAll(keepingCapacity:)&lt;/code&gt;가 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;swift&quot; style=&quot;background: #1e1e1e; color: #d4d4d4; padding: 16px; border-radius: 8px; overflow: auto;&quot;&gt;&lt;code&gt;extension UniqueArray where Element: ~Copyable {
  public init(
    capacity: Int? = nil,
    copying contents: some Sequence
  )

  public init(minimumCapacity: Int)

  public mutating func removeAll(keepingCapacity keepCapacity: Bool = false)
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;Source Compatibility&lt;/span&gt;&lt;/b&gt;&lt;/h2&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;RigidArray와 UniqueArray는 표준 라이브러리의 새 타입이라 추가는 소스 호환적인 변경이에요.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;swift-collections에서 이 타입들을 import하고 있거나 같은 이름으로 커스텀 타입을 정의한 개발자라도, 표준 라이브러리 타입 이름에 대한 shadowing 규칙 덕분에 기존 import/커스텀 타입은 그대로 동작합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;ABI Compatibility&lt;/span&gt;&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;이 제안은 표준 라이브러리 ABI에 순수하게 추가만 하는 변경이라 기존 바이너리를 깨지 않아요. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;두 타입은 frozen으로 제안되는데, 이는 향후 표현 방식 변경을 막습니다 (capacity 축소를 구현하려고 예약된 capacity를 추적하고 싶을 수 있는 &lt;code&gt;UniqueArray&lt;/code&gt;에 특히 관련이 있어요).&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;Implications on Adoption&lt;/span&gt;&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;code&gt;RigidArray&lt;/code&gt;와 &lt;code&gt;UniqueArray&lt;/code&gt;는 표준 라이브러리의 새 타입이므로, 적어도 이 타입들이 도입된 버전의 Swift를 써야 해요. &lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;swift-collections에서 이 타입들을 쓰던 개발자라면, 패키지 소스의 하위 배포 특성 때문에 계속 그 버전을 쓰는 게 더 나을 수도 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h2 style=&quot;border-left: 4px solid #3a8c28; padding-left: 12px; margin-top: 32px;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;Future Directions&lt;/span&gt;&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;Clonable&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;이 제안은 &lt;a href=&quot;https://github.com/swiftlang/swift-evolution/blob/main/proposals/0517-uniquebox.md&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;UniqueBox&lt;/a&gt; 제안처럼 &lt;code&gt;RigidArray&lt;/code&gt;와 &lt;code&gt;UniqueArray&lt;/code&gt; 모두에 &lt;code&gt;clone()&lt;/code&gt;/&lt;code&gt;clone(capacity:)&lt;/code&gt;를 도입해요. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;다만 지금은 &lt;code&gt;Element: Copyable&lt;/code&gt;을 요구해서 &lt;code&gt;UniqueArray&amp;lt;UniqueArray&amp;lt;Int&amp;gt;&amp;gt;&lt;/code&gt; 같은 중첩 2차원 배열은 불가능한데, &lt;code&gt;UniqueBox&lt;/code&gt; 제안에서 언급했듯 이런 기능을 가능하게 할 &lt;code&gt;Clonable&lt;/code&gt; 프로토콜의 여지가 있어요.&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;swift&quot; style=&quot;background: #1e1e1e; color: #d4d4d4; padding: 16px; border-radius: 8px; overflow: auto;&quot;&gt;&lt;code&gt;public protocol Cloneable: ~Copyable {
  func clone() -&amp;gt; Self
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;다른 표준 자료구조의 Rigid/Unique variant&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;이 제안이 도입하는 &lt;code&gt;Rigid&lt;/code&gt;/&lt;code&gt;Unique&lt;/code&gt; 접두어는 비슷한 동작을 하는 컨테이너 타입들의 일반적인 네이밍 패턴으로 자리잡길 의도한 것이에요. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;swift-collections 패키지는 이미 같은 시맨틱스의 ring buffer인 &lt;code&gt;RigidDeque&lt;/code&gt;, &lt;code&gt;UniqueDeque&lt;/code&gt;를 정의하고 있고, ownership-aware한 &lt;code&gt;Set&lt;/code&gt;/&lt;code&gt;Dictionary&lt;/code&gt; 프로토타입도 같은 접두어로 제공합니다. &lt;code&gt;RigidDeque&lt;/code&gt;, &lt;code&gt;UniqueDeque&lt;/code&gt;, &lt;code&gt;RigidSet&lt;/code&gt;, &lt;code&gt;UniqueSet&lt;/code&gt;, &lt;code&gt;RigidDictionary&lt;/code&gt;, &lt;code&gt;UniqueDictionary&lt;/code&gt; 모두 표준 라이브러리에 추가될 잠재적 후보들이에요.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;Container 프로토콜&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;이 제안이 두 배열 타입에 &lt;code&gt;BorrowingSequence&lt;/code&gt; 채택을 더하긴 하지만, 그 위에 컨테이너 프로토콜을 제안할 준비는 아직 안 됐어요. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;swift-collections에서 &lt;a href=&quot;https://github.com/apple/swift-collections/tree/1.4.1/Sources/ContainersPreview/Protocols/Container&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;이런 추상화를 위한 설계 접근을 탐색&lt;/a&gt; 중입니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;리터럴 초기화&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;제안된 배열 타입들은 원소가 copyable이든 아니든 &lt;code&gt;ExpressibleByArrayLiteral&lt;/code&gt;을 채택하지 않아요. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;기존 프로토콜은 variadic 이니셜라이저를 통한 &lt;code&gt;Array&lt;/code&gt; 인스턴스 구성 위에 만들어져 있어서 일반화하기 쉽지 않고, &lt;code&gt;RigidArray&lt;/code&gt;/&lt;code&gt;UniqueArray&lt;/code&gt; 초기화가 임시 &lt;code&gt;Array&lt;/code&gt; 인스턴스를 거치도록 강제하면 이 타입들의 성능 목표를 만족시킬 수 없어요. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;대신 target 타입 저장 버퍼 위의 &lt;code&gt;OutputSpan&lt;/code&gt; 인스턴스를 채우는 방식으로 배열 리터럴 초기화를 재구성하는 방법을 하나 생각해볼 수 있어요.&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;angelscript&quot; style=&quot;background: #1e1e1e; color: #d4d4d4; padding: 16px; border-radius: 8px; overflow: auto;&quot;&gt;&lt;code&gt;protocol ArrayLiterable: ~Copyable {
  associatedtype ArrayLiteralElement: ~Copyable

  init(
    arrayLiteralCount count: Int, 
    initializingWith initializer: (inout OutputSpan) throws(E) -&amp;gt; Void
  ) throws(E)
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;이 방식이라면 타입 컨텍스트 T에서 &lt;code&gt;[a, b, c, d]&lt;/code&gt; 같은 배열 초기화 표현이 대략 이렇게 확장될 거예요.&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;less&quot; style=&quot;background: #1e1e1e; color: #d4d4d4; padding: 16px; border-radius: 8px; overflow: auto;&quot;&gt;&lt;code&gt;T(arrayLiteralCount: 4) { target in
  target.append(a)
  target.append(b)
  target.append(c)
  target.append(d)
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;(T가 연속된 저장소를 갖는다고 가정한 것이고, 불연속적인 target 저장소를 초기화하도록 허용하는 건 항목을 반환하는 함수들의 inline array를 다루는 등 조금 더 까다로워요.) &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;이 방향이든 다른 방향이든, 후속 작업의 주제가 될 것으로 예상합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 style=&quot;border-left: 4px solid #3a8c28; padding-left: 12px; margin-top: 32px;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;Alternatives Considered&lt;/span&gt;&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;Allocator 인자와 비슷한 설정 값들&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;새 배열 타입을 제안하는 김에, 커스텀 allocator로 이 자료구조들을 할당할 수 있게 하는 방법도 고려했어요.&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;cpp&quot; style=&quot;background: #1e1e1e; color: #d4d4d4; padding: 16px; border-radius: 8px; overflow: auto;&quot;&gt;&lt;code&gt;public struct UniqueArray: ~Copyable {}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;allocator 제네릭 인자를 추가하는 건 C++이나 Rust의 컨테이너 타입과 비슷한 방식이에요. 이러려면 커스텀 allocator가 채택할 &lt;code&gt;Allocator&lt;/code&gt; 프로토콜과, 표준 라이브러리 기본으로 제공되는 &lt;code&gt;SystemAllocator&lt;/code&gt; 같은 것이 필요합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre class=&quot;swift&quot; style=&quot;background: #1e1e1e; color: #d4d4d4; padding: 16px; border-radius: 8px; overflow: auto;&quot;&gt;&lt;code&gt;protocol Allocator {
  func allocate(_: T.Type) -&amp;gt; UnsafeMutablePointer
  func deallocate(_: UnsafeMutablePointer)
  ...
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;하지만 이런 타입 인자는 함수 시그니처를 훨씬 번거롭게 만들어요.&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;ada&quot; style=&quot;background: #1e1e1e; color: #d4d4d4; padding: 16px; border-radius: 8px; overflow: auto;&quot;&gt;&lt;code&gt;func foo(_ x: borrowing UniqueArray)
// error: generic type 'UniqueArray' specialized with too few type parameters (got 1, but expected 2)&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;C++과 Rust는 제네릭 타입 매개변수에 기본값을 허용해서 이 문제를 풀지만, Swift에는 아직 그런 언어 기능이 없어요. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;설령 있다 해도 &lt;code&gt;foo(_:)&lt;/code&gt;가 시스템 allocator를 쓰도록 과도하게 제약해버리는 더 나쁜 문제가 생겨요. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;unique array를 그냥 borrow하는 함수는 어떤 allocator를 쓰는지 신경 쓸 이유가 없거든요 (어차피 mutate할 방법도 없으니까요). 결국 &lt;code&gt;foo&lt;/code&gt;도 제네릭이 되어야 합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre class=&quot;swift&quot; style=&quot;background: #1e1e1e; color: #d4d4d4; padding: 16px; border-radius: 8px; overflow: auto;&quot;&gt;&lt;code&gt;func foo(_ x: borrowing UniqueArray&amp;lt;Int, some Allocator&amp;gt;)&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;배열을 consume하거나 mutate하려는 함수라면 이 allocator 인자를 이름 붙여서 코드베이스 전체에 전파해야 하는 경우가 잦아, 인터페이스 정의를 오염시키고 코드를 흐릴 수 있어요. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;이런 타입 인자 오염은 C++ 개발자들의 흔한 불만이기도 하죠. 게&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;다가 &lt;code&gt;Allocator&lt;/code&gt; 추상화는 구현체가 copyable이어야 하는지, allocate/deallocate가 mutating으로 표시돼서 동시 사용과 호환이 안 되는 건 아닌지, 애초에 Swift 개발자들이 allocator를 어떻게 구현해야 하는지 같은 질문도 남겨요. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;무엇보다 allocator는 unsafe 포인터를 다루기 때문에 Swift 메모리 안전성 스토리에 눈에 띄는 구멍이 될 수 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;RigidArray/UniqueArray가 Array와 저장 표현을 공유하게 하기&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;UniqueArray는 사실 RigidArray 인스턴스를 감싼 얇은 wrapper 타입이라 서로  (1) 복잡도로 변환 가능해요.&lt;/span&gt;&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;클래식 &lt;code&gt;Array&lt;/code&gt;도 이 상호 변환 가능한 패밀리에 들어오면 좋겠지만, &lt;code&gt;Array&lt;/code&gt;의 저장 표현은 ABI의 일부라 변경할 수 없어요. &lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;code&gt;RigidArray&lt;/code&gt;/&lt;code&gt;UniqueArray&lt;/code&gt;가 tail-allocated 저장소를 갖는 특정 제네릭 클래스를 중심으로 지어진 그 표현을 그대로 빌려오는 건 부적절할 거예요. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;같은 표현을 쓰면 새 low-level 타입에 불필요한 성능 오버헤드가 생겨서 경쟁 시스템 프로그래밍 언어의 비슷한 타입들과 경쟁력이 떨어질 수 있습니다. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;그래서 &lt;code&gt;Array&lt;/code&gt;와 새 타입 사이의 변환은 새로 할당한 저장소로 원소를 복사/이동하는 선형 시간 연산이 필요하고, 실제로는 큰 문제가 되지 않을 것으로 봅니다&lt;/b&gt;.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;Array를 noncopyable 원소를 지원하도록 일반화하기&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;copy-on-write 값 시맨틱스가 Array와 다른 표준 Collection 타입들, 그리고 Swift 자체의 핵심 특징이라고 생각해요.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;code&gt;Array&lt;/code&gt;를 조건부로 noncopyable하게 만들거나 copy-on-write 동작을 조건화하는 건 Swift Ownership Manifesto의 목표에 오히려 반하고, 실제로도 실용적이지 않다고 봅니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;그리고 그런 작업을 하더라도 이 문서가 제안하는 전용 fixed-capacity/guaranteed-noncopyable 배열 variant의 필요성이 사라지진 않아요.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt; &lt;code&gt;Element&lt;/code&gt;가 copyable이라는 이유만으로 개발자에게 동적으로 크기가 조정되는 copy-on-write &lt;code&gt;Array&lt;/code&gt;를 강제하는 건 적절하지 않으니까요. &lt;code&gt;Array&lt;/code&gt;가 언젠가 noncopyable 콘텐츠를 지원하게 되든 안 되든, 정수용 &lt;code&gt;RigidArray&lt;/code&gt;나 float용 &lt;code&gt;UniqueArray&lt;/code&gt;에 대한 실질적이고 시급한 수요가 있습니다. 다만 이 제안이 그런 미래 작업을 막는 건 전혀 아니에요.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;이 타입들을 기본 Swift 모듈로 옮기기&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;이 타입들이 Swift 개발자의 기본 네임스페이스에 들어가야 한다고는 생각하지 않아요.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;Array는 여전히 모두의 첫 번째 선택이어야 하니까요.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;이 배열 타입들의 추가가 &lt;code&gt;Array&lt;/code&gt;를 대체하는 게 아니라, 더 제약된 환경에서 작업할 때 쓸 수 있는 대안적인 도구일 뿐입니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h2 style=&quot;border-left: 4px solid #3a8c28; padding-left: 12px; margin-top: 32px;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;Conclusion&lt;/span&gt;&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;SE-0527은 표준 라이브러리에 &lt;code&gt;RigidArray&lt;/code&gt;와 &lt;code&gt;UniqueArray&lt;/code&gt;라는 두 개의 noncopyable 지원 배열 타입을 가져다줘요. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;copy-on-write와 암묵적 resize라는 &lt;code&gt;Array&lt;/code&gt;의 두 특징을 각각 유연하게 켜고 끌 수 있게 설계된 셈인데, &lt;code&gt;RigidArray&lt;/code&gt;는 고정 capacity로 예측 가능한 성능을, &lt;code&gt;UniqueArray&lt;/code&gt;는 기하급수적 성장 곡선으로 편리한 동적 크기 조정을 제공합니다. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;둘 다 noncopyable 원소를 자연스럽게 담을 수 있어서, 그동안 &lt;code&gt;Array&lt;/code&gt;로는 손댈 수 없었던 고성능&amp;middot;저수준 영역에서 Swift가 훨씬 쓸모 있어질 것 같습니다  &lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h2 style=&quot;border-left: 4px solid #3a8c28; padding-left: 12px; margin-top: 32px;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;References&lt;/span&gt;&lt;/b&gt;&lt;/h2&gt;
&lt;figure id=&quot;og_1785628327727&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;object&quot; data-og-title=&quot;swift-evolution/proposals/0527-rigidarray-uniquearray.md at main &amp;middot; swiftlang/swift-evolution&quot; data-og-description=&quot;This maintains proposals for changes and user-visible enhancements to the Swift Programming Language. - swiftlang/swift-evolution&quot; data-og-host=&quot;github.com&quot; data-og-source-url=&quot;https://github.com/swiftlang/swift-evolution/blob/main/proposals/0527-rigidarray-uniquearray.md&quot; data-og-url=&quot;https://github.com/swiftlang/swift-evolution/blob/main/proposals/0527-rigidarray-uniquearray.md&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/G0k5v/dJMb8Z3Gcjl/ImgwAeLuLAuBqWxjnx26f1/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600,https://scrap.kakaocdn.net/dn/yYVuK/dJMb8Yp91PG/A3OoYHm0TqP3UeaOvzLnj0/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600&quot;&gt;&lt;a href=&quot;https://github.com/swiftlang/swift-evolution/blob/main/proposals/0527-rigidarray-uniquearray.md&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://github.com/swiftlang/swift-evolution/blob/main/proposals/0527-rigidarray-uniquearray.md&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/G0k5v/dJMb8Z3Gcjl/ImgwAeLuLAuBqWxjnx26f1/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600,https://scrap.kakaocdn.net/dn/yYVuK/dJMb8Yp91PG/A3OoYHm0TqP3UeaOvzLnj0/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;swift-evolution/proposals/0527-rigidarray-uniquearray.md at main &amp;middot; swiftlang/swift-evolution&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;This maintains proposals for changes and user-visible enhancements to the Swift Programming Language. - swiftlang/swift-evolution&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;github.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;</description>
      <category>Swift</category>
      <category>array</category>
      <category>noncopyable</category>
      <category>RigidArray</category>
      <category>SE-0527</category>
      <category>SWIFT</category>
      <category>UniqueArray</category>
      <author>GREEN.1229</author>
      <guid isPermaLink="true">https://green1229.tistory.com/631</guid>
      <comments>https://green1229.tistory.com/631#entry631comment</comments>
      <pubDate>Sun, 2 Aug 2026 08:53:35 +0900</pubDate>
    </item>
    <item>
      <title>[SE-0525] Safe loading API for RawSpan</title>
      <link>https://green1229.tistory.com/630</link>
      <description>&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Nanum Gothic';&quot;&gt;안녕하세요. &lt;span style=&quot;color: #409d00;&quot;&gt;&lt;b&gt;그린&lt;/b&gt;&lt;/span&gt;입니다  &lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #000000; font-family: 'Nanum Gothic';&quot;&gt;이번 포스팅에서는 &lt;span style=&quot;background-color: #9feec3;&quot;&gt;&lt;b&gt;SE-0525 &amp;mdash; RawSpan을 위한 안전한 로딩 API에 대해 정리&lt;/b&gt;&lt;/span&gt;해보겠습니다  &lt;/span&gt;&lt;span style=&quot;color: #000000; font-family: 'Nanum Gothic';&quot;&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;sadfs.001.jpeg&quot; data-origin-width=&quot;400&quot; data-origin-height=&quot;400&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/AQLht/dJMcafgrfPc/Ca52KdkItevhXPESPYu7xk/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/AQLht/dJMcafgrfPc/Ca52KdkItevhXPESPYu7xk/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/AQLht/dJMcafgrfPc/Ca52KdkItevhXPESPYu7xk/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FAQLht%2FdJMcafgrfPc%2FCa52KdkItevhXPESPYu7xk%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;400&quot; height=&quot;400&quot; data-filename=&quot;sadfs.001.jpeg&quot; data-origin-width=&quot;400&quot; data-origin-height=&quot;400&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h2 style=&quot;border-left: 4px solid #3a8c28; padding-left: 12px; margin-top: 32px;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #000000; font-family: 'Nanum Gothic';&quot;&gt;Intro&lt;/span&gt;&lt;/b&gt;&lt;/h2&gt;
&lt;div style=&quot;background: #f2f8ee; border-radius: 10px; padding: 16px 20px; margin: 16px 0;&quot;&gt;
&lt;p style=&quot;margin: 4px 0;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;Proposal:&lt;/b&gt; SE-0525&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;margin: 4px 0;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;Author:&lt;/b&gt; Guillaume Lessard&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;margin: 4px 0;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;Review Manager:&lt;/b&gt; Xiaodi Wu&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;margin: 4px 0;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;Status:&lt;/b&gt; Implemented (Swift 6.4)&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;margin: 4px 0;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;Related Proposals:&lt;/b&gt; SE-0447&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;h2 style=&quot;border-left: 4px solid #3a8c28; padding-left: 12px; margin-top: 32px;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #000000; font-family: 'Nanum Gothic';&quot;&gt;Motivation&lt;/span&gt;&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #000000; font-family: 'Nanum Gothic';&quot;&gt;SE-0447에서 &lt;code&gt;RawSpan&lt;/code&gt;을 도입하면서 임의 타입의 값을 로드할 수 있는 unsafe 함수들도 함께 들어왔어요  &lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Nanum Gothic';&quot;&gt;네이티브 정수 타입처럼 그중 일부는 로드해도 실제로 안전한데도, &lt;b&gt;&lt;code&gt;unsafe&lt;/code&gt;라는 표시 때문에 사용하는 입장에서는 늘 의심이 생기기 마련입니다  &lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Nanum Gothic';&quot;&gt;이번 제안은 &lt;b&gt;byte-loading 연산 중 안전한 것들을 명확히 구분해주는 게 목표&lt;/b&gt;예요. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Nanum Gothic';&quot;&gt;그리고 안전한 byte-loading을 정의하려면 안전한 byte-storing도 함께 정리해야 해서, 이 제안은 그 부분도 함께 다룹니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 style=&quot;border-left: 4px solid #3a8c28; padding-left: 12px; margin-top: 32px;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #000000; font-family: 'Nanum Gothic';&quot;&gt;Proposed Solution&lt;/span&gt;&lt;/b&gt;&lt;/h2&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;두 개의 새 프로토콜을 제안합니다.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;초기화된 타입 값과 초기화된 raw 바이트 사이의 변환을 지원하는 프로토콜&lt;/b&gt;이에요. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Nanum Gothic';&quot;&gt;하나는 항상 안전하게 raw 바이트로 읽을 수 있는 타입이 채택하는 &lt;code&gt;ConvertibleToBytes&lt;/code&gt;, 다른 하나는 raw 바이트에서 항상 안전하게 해석될 수 있는 타입이 채택하는 &lt;code&gt;ConvertibleFromBytes&lt;/code&gt;입니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #000000; font-family: 'Nanum Gothic';&quot;&gt;ConvertibleToBytes&lt;/span&gt;&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Nanum Gothic';&quot;&gt;어떤 타입의 값으로 메모리를 초기화할 때, 그 타입의 stride를 이루는 &lt;b&gt;모든 바이트가 초기화되어야 한다면 &lt;code&gt;ConvertibleToBytes&lt;/code&gt;를 채택할 수 있어요.&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;less&quot; style=&quot;background: #1e1e1e; color: #d4d4d4; padding: 16px; border-radius: 8px; overflow: auto;&quot;&gt;&lt;code&gt;@_marker protocol ConvertibleToBytes: Copyable {}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Nanum Gothic';&quot;&gt;메모리 표현에 패딩이 전혀 없는 타입, 즉 저장 프로퍼티 크기의 합이 stride와 같은 타입이 채택할 수 있습니다. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Nanum Gothic';&quot;&gt;예를 들어 &lt;code&gt;Optional&amp;lt;Int16&amp;gt;&lt;/code&gt;은 stride 4바이트 중 3바이트만 쓰기 때문에 채택할 수 없지만, &lt;code&gt;struct Pair { var a, b: Int16 }&lt;/code&gt;는 크기와 stride가 같아서 채택 가능해요.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;ConvertibleToBytes를 채택하려면 다음 조건을 만족해야 합니다.&lt;/span&gt;&lt;/blockquote&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000; font-family: 'Nanum Gothic';&quot;&gt;하나 이상의 저장 프로퍼티를 가질 것&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000; font-family: 'Nanum Gothic';&quot;&gt;모든 저장 프로퍼티가 &lt;code&gt;ConvertibleToBytes&lt;/code&gt;를 채택한 타입일 것&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000; font-family: 'Nanum Gothic';&quot;&gt;저장 프로퍼티들이 패딩 없이 메모리에 연속적으로 저장될 것&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000; font-family: 'Nanum Gothic';&quot;&gt;어떤 값도 자신의 바이트 일부를 무시하지 않을 것 (대부분의 enum이 여기서 제외됩니다)&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Nanum Gothic';&quot;&gt;표준 라이브러리의 많은 기본 타입은 이 프로토콜을 채택하지만, 표준 라이브러리 바깥의 타입은 처음에는 채택할 수 없어요. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #000000; font-family: 'Nanum Gothic';&quot;&gt;&lt;code&gt;ConvertibleToBytes&lt;/code&gt; 채택 선언은 그 타입을 담고 있는 모듈에서만 할 수 있습니다.&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #000000; font-family: 'Nanum Gothic';&quot;&gt;ConvertibleFromBytes&lt;/span&gt;&lt;/b&gt;&lt;/h3&gt;
&lt;pre class=&quot;less&quot; style=&quot;background: #1e1e1e; color: #d4d4d4; padding: 16px; border-radius: 8px; overflow: auto;&quot;&gt;&lt;code&gt;@_marker protocol ConvertibleFromBytes: BitwiseCopyable {}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #000000; font-family: 'Nanum Gothic';&quot;&gt;저장 프로퍼티를 이루는 모든 바이트의 모든 비트 패턴이 유효한 타입이라면 &lt;code&gt;ConvertibleFromBytes&lt;/code&gt;를 채택할 수 있어요. &lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Nanum Gothic';&quot;&gt;내부나 trailing 패딩이 있는 타입도 허용되지만, 저장 프로퍼티 값에 의미론적인 제약이 있으면 안 됩니다. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Nanum Gothic';&quot;&gt;예를 들어 &lt;code&gt;struct Point { var x, y: Int }&lt;/code&gt;는 x, y 사이에 아무 제약이 없어서 채택 가능하지만, &lt;code&gt;Range&amp;lt;Int&amp;gt;&lt;/code&gt;는 &lt;code&gt;lowerBound &amp;lt;= upperBound&lt;/code&gt;라는 의미론적 제약이 있어서 채택할 수 없어요.&lt;/span&gt;&lt;span style=&quot;color: #000000; font-family: 'Nanum Gothic';&quot;&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Nanum Gothic';&quot;&gt;&lt;code&gt;UnicodeScalar&lt;/code&gt;(일부 비트 패턴이 무효), 가상의 UTF8 &lt;code&gt;SmallString&lt;/code&gt;(바이트 순서가 유효성에 영향), &lt;code&gt;UnsafeRawPointer&lt;/code&gt;(런타임 전까지 값의 유효성을 알 수 없음) 등도 채택할 수 없는 예시예요.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Nanum Gothic';&quot;&gt;컴파일러가 &lt;code&gt;ConvertibleFromBytes&lt;/code&gt;의 의미론적 요구사항을 강제할 수 없기 때문에, 표준 라이브러리 바깥의 타입은 unchecked conformance로만 채택할 수 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;css&quot; style=&quot;background: #1e1e1e; color: #d4d4d4; padding: 16px; border-radius: 8px; overflow: auto;&quot;&gt;&lt;code&gt;extension MyType: @unchecked ConvertibleFromBytes {}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #000000; font-family: 'Nanum Gothic';&quot;&gt;FullyInhabited&lt;/span&gt;&lt;/b&gt;&lt;/h3&gt;
&lt;pre class=&quot;1c&quot; style=&quot;background: #1e1e1e; color: #d4d4d4; padding: 16px; border-radius: 8px; overflow: auto;&quot;&gt;&lt;code&gt;typealias FullyInhabited = ConvertibleToBytes &amp;amp; ConvertibleFromBytes&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Nanum Gothic';&quot;&gt;&lt;code&gt;ConvertibleToBytes&lt;/code&gt;와 &lt;code&gt;ConvertibleFromBytes&lt;/code&gt;의 교집합이에요.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #000000; font-family: 'Nanum Gothic';&quot;&gt;RawSpan과 MutableRawSpan&lt;/span&gt;&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Nanum Gothic';&quot;&gt;&lt;code&gt;RawSpan&lt;/code&gt;과 &lt;code&gt;MutableRawSpan&lt;/code&gt;에 제네릭한 &lt;code&gt;load(as:)&lt;/code&gt; 함수가 새로 생겨요. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Nanum Gothic';&quot;&gt;포인터 정렬 제약 없이 &lt;code&gt;ConvertibleFromBytes&lt;/code&gt; 값을 읽어올 수 있고, bounds-checked라서 이 함수는 안전합니다.&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;swift&quot; style=&quot;background: #1e1e1e; color: #d4d4d4; padding: 16px; border-radius: 8px; overflow: auto;&quot;&gt;&lt;code&gt;extension RawSpan {
  func load(
    fromByteOffset: Int,
    as: T.Type = T.self
  ) -&amp;gt; T
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Nanum Gothic';&quot;&gt;추가로, &lt;code&gt;ConvertibleFromBytes&lt;/code&gt;와 &lt;code&gt;FixedWidthInteger&lt;/code&gt;를 동시에 채택한 타입을 위해 byte order를 지정할 수 있는 버전도 있어요.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre class=&quot;swift&quot; style=&quot;background: #1e1e1e; color: #d4d4d4; padding: 16px; border-radius: 8px; overflow: auto;&quot;&gt;&lt;code&gt;extension RawSpan {
  func load(
    fromByteOffset: Int,
    as: T.Type = T.self,
    _ byteOrder: ByteOrder
  ) -&amp;gt; T
}

@frozen
enum ByteOrder: Equatable, Hashable, Sendable {
  case bigEndian, littleEndian
  
  static var native: Self { get }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Nanum Gothic';&quot;&gt;&lt;code&gt;ConvertibleFromBytes &amp;amp; FixedWidthInteger&lt;/code&gt;를 채택하는 표준 라이브러리 타입 목록은 &lt;code&gt;UInt8&lt;/code&gt;, &lt;code&gt;Int8&lt;/code&gt;, &lt;code&gt;UInt16&lt;/code&gt;, &lt;code&gt;Int16&lt;/code&gt;, &lt;code&gt;UInt32&lt;/code&gt;, &lt;code&gt;Int32&lt;/code&gt;, &lt;code&gt;UInt64&lt;/code&gt;, &lt;code&gt;Int64&lt;/code&gt;, &lt;code&gt;UInt&lt;/code&gt;, &lt;code&gt;Int&lt;/code&gt;, &lt;code&gt;UInt128&lt;/code&gt;, &lt;code&gt;Int128&lt;/code&gt;이에요. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Nanum Gothic';&quot;&gt;이 &lt;code&gt;load(as:)&lt;/code&gt; 함수들은 atomic 연산이 아니고, unchecked byte offset 버전은 제공되지 않아요 (필요하면 기존 &lt;code&gt;unsafeLoad(fromUncheckedByteOffset:as:)&lt;/code&gt;를 쓰면 됩니다).&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #000000; font-family: 'Nanum Gothic';&quot;&gt;RawSpan 계열의 subscript&lt;/span&gt;&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Nanum Gothic';&quot;&gt;&lt;code&gt;UInt8&lt;/code&gt;을 위한 편의 기능으로, 기존 &lt;code&gt;Span&lt;/code&gt;, &lt;code&gt;MutableSpan&lt;/code&gt;, &lt;code&gt;OutputSpan&lt;/code&gt;과 비슷한 subscript를 &lt;code&gt;RawSpan&lt;/code&gt;, &lt;code&gt;MutableRawSpan&lt;/code&gt;, &lt;code&gt;OutputRawSpan&lt;/code&gt;에도 정의합니다.&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;swift&quot; style=&quot;background: #1e1e1e; color: #d4d4d4; padding: 16px; border-radius: 8px; overflow: auto;&quot;&gt;&lt;code&gt;extension RawSpan {
  subscript(_ byteOffset: Int) -&amp;gt; UInt8 { get }
  
  @unsafe
  subscript(unchecked byteOffset: Int) -&amp;gt; UInt8 { get }
}

extension MutableRawSpan {
  subscript(_ byteOffset: Int) -&amp;gt; UInt8 { get set }

  @unsafe
  subscript(unchecked byteOffset: Int) -&amp;gt; UInt8 { get set }
}

extension OutputRawSpan {
  subscript(_ byteOffset: Int) -&amp;gt; UInt8 { get set }

  @unsafe
  subscript(unchecked byteOffset: Int) -&amp;gt; UInt8 { get set }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #000000; font-family: 'Nanum Gothic';&quot;&gt;MutableRawSpan과 OutputRawSpan&lt;/span&gt;&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Nanum Gothic';&quot;&gt;&lt;code&gt;MutableRawSpan&lt;/code&gt;에는 &lt;code&gt;storeBytes()&lt;/code&gt;의 새 오버로드가 추가돼요.&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;swift&quot; style=&quot;background: #1e1e1e; color: #d4d4d4; padding: 16px; border-radius: 8px; overflow: auto;&quot;&gt;&lt;code&gt;extension MutableRawSpan {
  mutating func storeBytes(
    of value: T,
    toByteOffset offset: Int,
    as type: T.Type,
    _ byteOrder: ByteOrder
  ) where T: ConvertibleToBytes &amp;amp; BitwiseCopyable &amp;amp; FixedWidthInteger
  
  @unsafe
  mutating func storeBytes(
    repeating repeatedValue: T,
    count: Int,
    as type: T.Type
  ) where T: BitwiseCopyable

  mutating func storeBytes(
    repeating repeatedValue: T,
    count: Int,
    as type: T.Type,
    _ byteOrder: ByteOrder
  ) where T: ConvertibleToBytes &amp;amp; BitwiseCopyable &amp;amp; FixedWidthInteger
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Nanum Gothic';&quot;&gt;기존 &lt;code&gt;T: BitwiseCopyable&lt;/code&gt;로 제약된 &lt;code&gt;storeBytes&lt;/code&gt; 함수는 &lt;code&gt;@unsafe&lt;/code&gt;로 표시됩니다. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Nanum Gothic';&quot;&gt;컴파일러 최적화로 인해 초기화되지 않은 바이트가 생길 수 있기 때문이에요. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Nanum Gothic';&quot;&gt;반복 저장 variant도 이번에 추가되는데, 이것도 &lt;code&gt;@unsafe&lt;/code&gt;로 표시됩니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;OutputRawSpan에는 대응하는 append() 함수가 생겨요.&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;/blockquote&gt;
&lt;pre class=&quot;swift&quot; style=&quot;background: #1e1e1e; color: #d4d4d4; padding: 16px; border-radius: 8px; overflow: auto;&quot;&gt;&lt;code&gt;extension OutputRawSpan {
  mutating func append(
    _ value: T,
    as type: T.Type
  ) where T: ConvertibleToBytes &amp;amp; BitwiseCopyable

  mutating func append(
    _ value: T,
    as type: T.Type,
    _ byteOrder: ByteOrder
  ) where T: ConvertibleToBytes &amp;amp; BitwiseCopyable &amp;amp; FixedWidthInteger
  
  mutating func append(
    repeating repeatedValue: T,
    count: Int,
    as type: T.Type
  ) where T: ConvertibleToBytes &amp;amp; BitwiseCopyable
  
  mutating func append(
    repeating repeatedValue: T,
    count: Int,
    as type: T.Type,
    _ byteOrder: ByteOrder
  ) where T: ConvertibleToBytes &amp;amp; BitwiseCopyable &amp;amp; FixedWidthInteger
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Nanum Gothic';&quot;&gt;기존 &lt;code&gt;T: BitwiseCopyable&lt;/code&gt;만으로 제약된 &lt;code&gt;append&lt;/code&gt; 함수도 &lt;code&gt;@unsafe&lt;/code&gt;로 표시됩니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;border-left: 4px solid #3a8c28; background: #f2f8ee; padding: 8px 16px; margin: 16px 0;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Nanum Gothic';&quot;&gt;여기서 제안하는 타입들의 메모리 레이아웃은 컴파일러/라이브러리 버전에 걸쳐 안정적이라고 보장되진 않아요. &lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;border-left: 4px solid #3a8c28; background: #f2f8ee; padding: 8px 16px; margin: 16px 0;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Nanum Gothic';&quot;&gt;실&lt;/span&gt;&lt;span style=&quot;color: #000000; font-family: 'Nanum Gothic';&quot;&gt;행 중인 프로세스끼리 데이터를 주고받거나 같은 프로세스에서 나중에 쓰려고 저장하는 용도라면 문제없지만, 네트워크 통신이나 파일 시스템 저장을 위한 직렬화처럼 더 정교한 용도에는 이 API가 building block 정도로만 쓰일 수 있어요.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #000000; font-family: 'Nanum Gothic';&quot;&gt;Span과 MutableSpan&lt;/span&gt;&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Nanum Gothic';&quot;&gt;&lt;code&gt;Span&lt;/code&gt;에는 &lt;code&gt;init(viewing: RawSpan)&lt;/code&gt; 이니셜라이저가 새로 생겨서, &lt;code&gt;Span.Element&lt;/code&gt;가 &lt;code&gt;ConvertibleFromBytes&lt;/code&gt;를 채택했다면 정렬되지 않은 raw 메모리 범위를 typed &lt;code&gt;Span&lt;/code&gt;으로 볼 수 있어요. 정렬과 bounds를 검사하는데, &lt;code&gt;RawSpan&lt;/code&gt;의 포인터 정렬이 &lt;code&gt;Element&lt;/code&gt;에 맞지 않거나 bounds가 stride의 배수가 아니면 트랩이 발생합니다.&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;kotlin&quot; style=&quot;background: #1e1e1e; color: #d4d4d4; padding: 16px; border-radius: 8px; overflow: auto;&quot;&gt;&lt;code&gt;extension Span {
  @_lifetime(copy bytes)
  init(viewing bytes: RawSpan) where Element: ConvertibleFromBytes
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Nanum Gothic';&quot;&gt;&lt;code&gt;MutableSpan&lt;/code&gt;에도 &lt;code&gt;MutableRawSpan&lt;/code&gt;의 메모리를 typed &lt;code&gt;MutableSpan&lt;/code&gt;처럼 mutate할 수 있는 이니셜라이저가 추가돼요. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #000000; font-family: 'Nanum Gothic';&quot;&gt;마찬가지로 정렬과 bounds를 검사해서 맞지 않으면 트랩합니다.&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;pre class=&quot;less&quot; style=&quot;background: #1e1e1e; color: #d4d4d4; padding: 16px; border-radius: 8px; overflow: auto;&quot;&gt;&lt;code&gt;extension MutableSpan {
  @_lifetime(&amp;amp;mutableBytes)
  init(mutating mutableBytes: inout MutableRawSpan)
    where Element: ConvertibleToBytes &amp;amp; ConvertibleFromBytes

  @_lifetime(copy mutableBytes)
  init(mutableBytes: consuming MutableRawSpan)
    where Element: ConvertibleToBytes &amp;amp; ConvertibleFromBytes
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Nanum Gothic';&quot;&gt;&lt;code&gt;RawSpan&lt;/code&gt;에서 &lt;code&gt;Span&lt;/code&gt;으로의 변환은 정렬이 잘 맞고 네이티브 byte order인 경우만 지원해요. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Nanum Gothic';&quot;&gt;더 복잡한 파싱이 필요하다면 &lt;a style=&quot;color: #000000;&quot; href=&quot;https://github.com/apple/swift-binary-parsing&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;swift-binary-parsing&lt;/a&gt; 패키지의 &lt;code&gt;ParserSpan&lt;/code&gt; 타입을 참고하면 됩니다. &lt;code&gt;RawSpan&lt;/code&gt;의 메모리 정렬을 확인하는 기능은 추후 별도 제안으로 다뤄질 예정이에요.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Nanum Gothic';&quot;&gt;기존 &lt;code&gt;bytes&lt;/code&gt;, &lt;code&gt;mutableBytes&lt;/code&gt; accessor도 &lt;code&gt;Element&lt;/code&gt;가 각각 &lt;code&gt;ConvertibleToBytes&lt;/code&gt;, &lt;code&gt;ConvertibleToBytes &amp;amp; ConvertibleFromBytes&lt;/code&gt;를 채택했을 때 안전한 오버로드를 갖게 됩니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 style=&quot;border-left: 4px solid #3a8c28; padding-left: 12px; margin-top: 32px;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #000000; font-family: 'Nanum Gothic';&quot;&gt;Detailed Design&lt;/span&gt;&lt;/b&gt;&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #000000; font-family: 'Nanum Gothic';&quot;&gt;표준 라이브러리 채택 목록&lt;/span&gt;&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;여러 정수/부동소수점 타입, &lt;code&gt;Duration&lt;/code&gt;, &lt;code&gt;InlineArray&lt;/code&gt;, &lt;code&gt;CollectionOfOne&lt;/code&gt;, 여러 &lt;code&gt;SIMD&lt;/code&gt; 타입, 범위 타입 일부, &lt;code&gt;Bool&lt;/code&gt;, &lt;code&gt;ObjectIdentifier&lt;/code&gt;, 각종 포인터 타입 등에 다음과 같이 채택이 추가&lt;/b&gt;됩니다.&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;puppet&quot; style=&quot;background: #1e1e1e; color: #d4d4d4; padding: 16px; border-radius: 8px; overflow: auto;&quot;&gt;&lt;code&gt;extension UInt8:   ConvertibleToBytes, ConvertibleFromBytes {}
extension Int8:    ConvertibleToBytes, ConvertibleFromBytes {}
extension UInt16:  ConvertibleToBytes, ConvertibleFromBytes {}
extension Int16:   ConvertibleToBytes, ConvertibleFromBytes {}
extension UInt32:  ConvertibleToBytes, ConvertibleFromBytes {}
extension Int32:   ConvertibleToBytes, ConvertibleFromBytes {}
extension UInt64:  ConvertibleToBytes, ConvertibleFromBytes {}
extension Int64:   ConvertibleToBytes, ConvertibleFromBytes {}
extension UInt:    ConvertibleToBytes, ConvertibleFromBytes {}
extension Int:     ConvertibleToBytes, ConvertibleFromBytes {}

extension UInt128: ConvertibleToBytes, ConvertibleFromBytes {}
extension Int128:  ConvertibleToBytes, ConvertibleFromBytes {}

extension Float16: ConvertibleToBytes, ConvertibleFromBytes {}
extension Float32: ConvertibleToBytes, ConvertibleFromBytes {} // 'Float'
extension Float64: ConvertibleToBytes, ConvertibleFromBytes {} // 'Double'

extension Duration: ConvertibleToBytes, ConvertibleFromBytes {}

extension InlineArray: ConvertibleToBytes
  where Element: ConvertibleToBytes {}
extension InlineArray: ConvertibleFromBytes
  where Element: ConvertibleFromBytes {}

extension CollectionOfOne: ConvertibleToBytes
  where Element: ConvertibleToBytes {}
extension CollectionOfOne: ConvertibleFromBytes
  where Element: ConvertibleFromBytes {}

extension SIMD2: ConvertibleToBytes
  where Scalar: ConvertibleToBytes {}
extension SIMD4: ConvertibleToBytes
  where Scalar: ConvertibleToBytes {}
extension SIMD8: ConvertibleToBytes
  where Scalar: ConvertibleToBytes {}
extension SIMD16: ConvertibleToBytes
  where Scalar: ConvertibleToBytes {}
extension SIMD32: ConvertibleToBytes
  where Scalar: ConvertibleToBytes {}
extension SIMD64: ConvertibleToBytes
  where Scalar: ConvertibleToBytes {}

extension SIMD2: ConvertibleFromBytes
  where Scalar: ConvertibleFromBytes {}
extension SIMD3: ConvertibleFromBytes
  where Scalar: ConvertibleFromBytes {}
extension SIMD4: ConvertibleFromBytes
  where Scalar: ConvertibleFromBytes {}
extension SIMD8: ConvertibleFromBytes
  where Scalar: ConvertibleFromBytes {}
extension SIMD16: ConvertibleFromBytes
  where Scalar: ConvertibleFromBytes {}
extension SIMD32: ConvertibleFromBytes
  where Scalar: ConvertibleFromBytes {}
extension SIMD64: ConvertibleFromBytes
  where Scalar: ConvertibleFromBytes {}

extension ClosedRange: ConvertibleToBytes
  where Bound: ConvertibleToBytes {}
extension Range: ConvertibleToBytes
  where Bound: ConvertibleToBytes {}

extension PartialRangeFrom: ConvertibleToBytes
  where Bound: ConvertibleToBytes {}
extension PartialRangeFrom.Iterator: ConvertibleToBytes
  where Bound: ConvertibleToBytes {}
extension PartialRangeThrough: ConvertibleToBytes
  where Bound: ConvertibleToBytes {}
extension PartialRangeUpTo: ConvertibleToBytes
  where Bound: ConvertibleToBytes {}

extension Bool: ConvertibleToBytes {}
extension ObjectIdentifier: ConvertibleToBytes {}

extension UnsafePointer: ConvertibleToBytes {}
extension UnsafeMutablePointer: ConvertibleToBytes {}
extension UnsafeRawPointer: ConvertibleToBytes {}
extension UnsafeMutableRawPointer: ConvertibleToBytes {}
extension OpaquePointer: ConvertibleToBytes {}

extension UnsafeBufferPointer: ConvertibleToBytes {}
extension UnsafeMutableBufferPointer: ConvertibleToBytes {}
extension UnsafeRawBufferPointer: ConvertibleToBytes {}
extension UnsafeMutableRawBufferPointer: ConvertibleToBytes {}&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;border-left: 4px solid #3a8c28; background: #f2f8ee; padding: 8px 16px; margin: 16px 0;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Nanum Gothic';&quot;&gt;위 목록 중 &lt;code&gt;BitwiseCopyable&lt;/code&gt; 채택이 없던 타입은 이번에 함께 채택하게 됩니다. &lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;border-left: 4px solid #3a8c28; background: #f2f8ee; padding: 8px 16px; margin: 16px 0;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Nanum Gothic';&quot;&gt;그리고 &lt;code&gt;SIMD3&lt;/code&gt;는 &lt;code&gt;SIMD4&lt;/code&gt;와 저장 공간이 같지만 한 원소만큼 tail padding이 있어서 &lt;code&gt;ConvertibleToBytes&lt;/code&gt;를 채택하지 못해요.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #000000; font-family: 'Nanum Gothic';&quot;&gt;안전한 최상위 bitCast 함수&lt;/span&gt;&lt;/b&gt;&lt;/h3&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;두 프로토콜 덕분에 타입을 안전하게 재해석하는 함수도 정의할 수 있게 됐어요.&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;/blockquote&gt;
&lt;pre class=&quot;swift&quot; style=&quot;background: #1e1e1e; color: #d4d4d4; padding: 16px; border-radius: 8px; overflow: auto;&quot;&gt;&lt;code&gt;func bitCast&amp;lt;T, U&amp;gt;(_ original: T, to type: U.Type) -&amp;gt; U
  where T: ConvertibleToBytes, U: ConvertibleFromBytes&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #000000; font-family: 'Nanum Gothic';&quot;&gt;Source Compatibility&lt;/span&gt;&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Nanum Gothic';&quot;&gt;이번 제안은 &lt;b&gt;오직 추가로만 이루어져 있어서 소스 호환성을 유지&lt;/b&gt;합니다. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Nanum Gothic';&quot;&gt;다만 오버로드를 추가하는 건 언제나 리스크가 있어서, 기존의 유효한 코드에 영향을 줄 가능성도 있어요. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Nanum Gothic';&quot;&gt;중대한 호환성 이슈가 없는지 확인하려면 테스트가 필요합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #000000; font-family: 'Nanum Gothic';&quot;&gt;ABI Compatibility&lt;/span&gt;&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;이번에 추가되는 함수들은 추가 ABI를 만들지 않는 방식으로 구현될 예정&lt;/b&gt;이에요. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Nanum Gothic';&quot;&gt;이 함수들은 &lt;code&gt;Span&lt;/code&gt;의 존재를 전제로 하기 때문에, Darwin 플랫폼에서는 Swift 표준 라이브러리가 OS와 함께 배포되는 만큼 최소 배포 타깃이 있습니다. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Nanum Gothic';&quot;&gt;&lt;code&gt;ByteOrder&lt;/code&gt;는 새 타입이라 자체 availability를 가지며, &lt;code&gt;ByteOrder&lt;/code&gt; 인자를 쓰는 함수들도 같은 availability를 공유합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #000000; font-family: 'Nanum Gothic';&quot;&gt;Implications on Adoption&lt;/span&gt;&lt;/b&gt;&lt;/h2&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;이번 제안의 추가 사항들은 새 버전의 Swift 표준 라이브러리를 필요로 합니다.&lt;/span&gt;&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 style=&quot;border-left: 4px solid #3a8c28; padding-left: 12px; margin-top: 32px;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #000000; font-family: 'Nanum Gothic';&quot;&gt;Future Directions&lt;/span&gt;&lt;/b&gt;&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #000000; font-family: 'Nanum Gothic';&quot;&gt;ConvertibleToBytes 프로토콜에 대한 검증&lt;/span&gt;&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Nanum Gothic';&quot;&gt;&lt;code&gt;ConvertibleToBytes&lt;/code&gt; 채택은 나중에 컴파일러가 추가로 검증하게 될 거예요. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Nanum Gothic';&quot;&gt;이 프로토콜은 addressable 메모리 상의 레이아웃에만 의존하기 때문에 컴파일 타임에 완전히 검증할 수 있고, &lt;code&gt;BitwiseCopyable&lt;/code&gt;처럼 자동화도 가능할 것으로 보입니다. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Nanum Gothic';&quot;&gt;검증과 함께, 패딩 대신 저장된 null 바이트를 자동으로 넣어주는 방식도 고려할 수 있어요.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #000000; font-family: 'Nanum Gothic';&quot;&gt;ConvertibleFromBytes 프로토콜에 대한 부분적 검증&lt;/span&gt;&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;&lt;code&gt;ConvertibleFromBytes&lt;/code&gt; 채택도 나중에 어느 정도 검증될 수 있어요.&lt;/b&gt; 컴&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Nanum Gothic';&quot;&gt;파일러는 모든 저장 프로퍼티가 &lt;code&gt;ConvertibleFromBytes&lt;/code&gt;를 채택했는지는 강제할 수 있지만, 의미론적 제약의 부재까지 직접 강제할 순 없습니다. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Nanum Gothic';&quot;&gt;다만 모든 저장 프로퍼티가 &lt;code&gt;public&lt;/code&gt;이고 &lt;code&gt;var&lt;/code&gt;인 경우처럼 우회적인 방법을 받아들일 수도 있어요.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #000000; font-family: 'Nanum Gothic';&quot;&gt;C에서 import된 타입 지원&lt;/span&gt;&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #000000; font-family: 'Nanum Gothic';&quot;&gt;Clang importer가 어떤 기본 C 타입이 이 프로토콜들을 지원하는지 알도록 만들 수도 있어요. &lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Nanum Gothic';&quot;&gt;aggregate C 타입에 대해서도 이 프로토콜 채택을 선언할 방법이 있으면 좋겠는데, 이를 위해 &quot;채택 선언은 타입을 담은 모듈에서만 가능하다&quot;는 제약을 import된 C 타입에 한해 완화하는 것도 유용할 것 같습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #000000; font-family: 'Nanum Gothic';&quot;&gt;튜플 지원&lt;/span&gt;&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Nanum Gothic';&quot;&gt;&lt;code&gt;ConvertibleToBytes&lt;/code&gt; 타입으로 구성된 튜플은 그 자체로 &lt;code&gt;ConvertibleToBytes&lt;/code&gt;여야 하고, &lt;code&gt;ConvertibleFromBytes&lt;/code&gt;도 마찬가지예요.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #000000; font-family: 'Nanum Gothic';&quot;&gt;RawSpan의 정렬 상태를 확인하는 유틸리티&lt;/span&gt;&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Nanum Gothic';&quot;&gt;&lt;code&gt;Span&lt;/code&gt; 이니셜라이저들은 올바르게 정렬된 &lt;code&gt;RawSpan&lt;/code&gt;을 요구하는데, 특정 타입에 대해 잘 정렬된 오프셋을 확인하는 유틸리티가 있으면 좋을 것 같다고 제안하고 있어요.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #000000; font-family: 'Nanum Gothic';&quot;&gt;@unsafe 함수/프로퍼티 이름 재정비&lt;/span&gt;&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Nanum Gothic';&quot;&gt;이전 제안에서 도입된 일부 함수/프로퍼티는 나중에 unsafe로 표시됐지만, 이름 자체에는 그 사실이 드러나지 않아요. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Nanum Gothic';&quot;&gt;strict memory safety 모드가 꺼져 있어도 unsafe함을 드러내는 이름들을 식별해서, 별도 제안을 통해 최소한의 혼란으로 이름을 바꾸는 계획이 필요합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #000000; font-family: 'Nanum Gothic';&quot;&gt;OutputSpan과 OutputRawSpan 사이의 append 지원&lt;/span&gt;&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Nanum Gothic';&quot;&gt;원래 이 제안에는 &lt;code&gt;Element&lt;/code&gt;가 &lt;code&gt;ConvertibleFromBytes&lt;/code&gt;일 때 &lt;code&gt;OutputRawSpan&lt;/code&gt;으로 &lt;code&gt;OutputSpan&lt;/code&gt;의 일부에 append하는 함수도 포함되어 있었어요.&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;stata&quot; style=&quot;background: #1e1e1e; color: #d4d4d4; padding: 16px; border-radius: 8px; overflow: auto;&quot;&gt;&lt;code&gt;span.append(upTo: capacity) { for _ in 0..&amp;lt;$0.capacity { $0.append(UInt8.zero) } }&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Nanum Gothic';&quot;&gt;capacity를 위한 인자 레이블(여기선 &quot;upTo&quot;)을 정하는 게 까다로운 주제라, &lt;code&gt;UniqueArray&lt;/code&gt;의 &lt;code&gt;insert&lt;/code&gt;, &lt;code&gt;replace&lt;/code&gt;, &lt;code&gt;append&lt;/code&gt;에도 같은 형태의 API가 필요하다는 점을 짚었어요.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Nanum Gothic';&quot;&gt;이 네이밍은 &lt;a style=&quot;color: #000000;&quot; href=&quot;https://github.com/swiftlang/swift-evolution/blob/main/proposals/0527-rigidarray-uniquearray.md&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;SE-0527&lt;/a&gt;(UniqueArray와 RigidArray) 쪽에서 충분히 논의된 뒤, &lt;code&gt;OutputSpan&lt;/code&gt;과 &lt;code&gt;OutputRawSpan&lt;/code&gt;에 적절한 variant와 함께 추가하자는 방향으로 정리됐습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 style=&quot;border-left: 4px solid #3a8c28; padding-left: 12px; margin-top: 32px;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #000000; font-family: 'Nanum Gothic';&quot;&gt;Alternatives Considered&lt;/span&gt;&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #000000; font-family: 'Nanum Gothic';&quot;&gt;함수 이름에 로드할 타입 이름을 인코딩하기&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Nanum Gothic';&quot;&gt;&lt;code&gt;loadInt32(fromByteOffset:_:)&lt;/code&gt;, &lt;code&gt;storeBytes(int32:toByteOffset:_:)&lt;/code&gt;처럼 구체적인 함수들을 따로 만들면 오버로드 문제를 피할 수 있어서 타입 체커 입장에서는 더 편할 수 있어요.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #000000; font-family: 'Nanum Gothic';&quot;&gt;컴파일러가 검증하는 ConvertibleToBytes 레이아웃 제약을 기다리기&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Nanum Gothic';&quot;&gt;이 제안이 다루는 기능은 시급하고, 표준 라이브러리 추가만으로도 달성할 수 있어요. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Nanum Gothic';&quot;&gt;&lt;code&gt;ConvertibleToBytes&lt;/code&gt; 레이아웃 제약의 검증에는 상당한 컴파일러 작업이 필요한데, 이 문서가 제안하는 API만으로도 충분히 가치가 있다고 판단했습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #000000; font-family: 'Nanum Gothic';&quot;&gt;FixedWidthInteger &amp;amp; BitwiseCopyable, BinaryFloatingPoint &amp;amp; BitwiseCopyable로 제네릭화하기&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Nanum Gothic';&quot;&gt;이 프로토콜들은 채택자가 완전히 inhabited되어야 한다는 걸 보장하지 않아서 충분한 제약이 아니에요.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #000000; font-family: 'Nanum Gothic';&quot;&gt;FullyInhabited 프로토콜 하나만 추가하기&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Nanum Gothic';&quot;&gt;이 제안의 두 번째 pitch에서는 &lt;code&gt;FullyInhabited&lt;/code&gt; 하나만 제안했었어요. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Nanum Gothic';&quot;&gt;논의 결과 결국 두 프로토콜 쌍이 필요하다는 게 드러났고, 구현 부담도 비슷했기 때문에 두 프로토콜을 각각 구현하는 쪽이 더 나은 선택으로 정리됐습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #000000; font-family: 'Nanum Gothic';&quot;&gt;ByteOrder 파라미터 생략하기&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Nanum Gothic';&quot;&gt;표준 라이브러리의 &lt;code&gt;FixedWidthInteger&lt;/code&gt;에는 &lt;code&gt;.bigEndian&lt;/code&gt;, &lt;code&gt;.littleEndian&lt;/code&gt; 계산 프로퍼티가 있어서 이를 활용할 수도 있었어요. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Nanum Gothic';&quot;&gt;하지만 이 프로퍼티들은 &lt;code&gt;Self&lt;/code&gt;를 반환해서 byte ordering과 유효한 값 자체를 혼동시키기 때문에 명확하지 않아요. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #000000; font-family: 'Nanum Gothic';&quot;&gt;이 제안은 byte ordering을 직렬화라는, 원래 있어야 할 자리에 적용합니다.&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #000000; font-family: 'Nanum Gothic';&quot;&gt;안전한 load() 함수를 정렬된 연산으로 기본 설정하기&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Nanum Gothic';&quot;&gt;&lt;code&gt;UnsafeRawPointer&lt;/code&gt;의 원래 &lt;code&gt;load()&lt;/code&gt;는 올바른 정렬을 요구했고, 나중에야 덜 제한적인 &lt;code&gt;loadUnaligned()&lt;/code&gt;가 추가됐어요. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Nanum Gothic';&quot;&gt;이건 오랫동안 아쉬운 부분으로 여겨져 왔고, 이번 제안은 새 안전한 &lt;code&gt;load()&lt;/code&gt; 함수들이 정렬되지 않은 연산을 수행하도록 만들어서 이를 개선하려 하고 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #000000; font-family: 'Nanum Gothic';&quot;&gt;toByteOffset, fromByteOffset 파라미터를 0으로 기본값 설정하기&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Nanum Gothic';&quot;&gt;원래는 이 파라미터들에 기본값을 두려고 했는데, 그러면 &lt;code&gt;RawSpan&lt;/code&gt;이나 &lt;code&gt;MutableRawSpan&lt;/code&gt;의 전체 길이를 반드시 써야 한다는 인상을 줄 수 있다는 지적이 있었어요. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Nanum Gothic';&quot;&gt;비슷한 기존 unsafe API에는 이미 기본값이 있다는 점을 감안해서, 이 결정은 나중에 조율이 필요할 수 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 style=&quot;border-left: 4px solid #3a8c28; padding-left: 12px; margin-top: 32px;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #000000; font-family: 'Nanum Gothic';&quot;&gt;Conclusion&lt;/span&gt;&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #000000; font-family: 'Nanum Gothic';&quot;&gt;&lt;code&gt;ConvertibleToBytes&lt;/code&gt;와 &lt;code&gt;ConvertibleFromBytes&lt;/code&gt; 프로토콜 덕분에 그동안 &lt;code&gt;unsafe&lt;/code&gt; 딱지가 붙어 있던 &lt;code&gt;RawSpan&lt;/code&gt; byte-loading이 명확하게 안전한 영역과 그렇지 않은 영역으로 나뉘게 됐어요. &lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Nanum Gothic';&quot;&gt;정수, 부동소수점, SIMD, 포인터 타입 등 표준 라이브러리의 많은 타입이 바로 이 프로토콜들을 채택하고, 안전한 &lt;code&gt;bitCast&lt;/code&gt;까지 함께 따라오면서 프로세스 간 데이터 전달이나 파싱 유틸리티를 만들 때 훨씬 믿음직한 building block이 생긴 셈입니다  &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 style=&quot;border-left: 4px solid #3a8c28; padding-left: 12px; margin-top: 32px;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #000000; font-family: 'Nanum Gothic';&quot;&gt;References&lt;/span&gt;&lt;/b&gt;&lt;/h2&gt;
&lt;figure id=&quot;og_1785026198048&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;object&quot; data-og-title=&quot;swift-evolution/proposals/0525-rawspan-safe-loading-api.md at main &amp;middot; swiftlang/swift-evolution&quot; data-og-description=&quot;This maintains proposals for changes and user-visible enhancements to the Swift Programming Language. - swiftlang/swift-evolution&quot; data-og-host=&quot;github.com&quot; data-og-source-url=&quot;https://github.com/swiftlang/swift-evolution/blob/main/proposals/0525-rawspan-safe-loading-api.md&quot; data-og-url=&quot;https://github.com/swiftlang/swift-evolution/blob/main/proposals/0525-rawspan-safe-loading-api.md&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/d72kXJ/dJMb8RkfOpK/yKKBP6NU9Fy5j8GEglADA1/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600,https://scrap.kakaocdn.net/dn/GsVnz/dJMb9g5or29/BGBkCE5R8dUNpI5VE5m5BK/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600&quot;&gt;&lt;a href=&quot;https://github.com/swiftlang/swift-evolution/blob/main/proposals/0525-rawspan-safe-loading-api.md&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://github.com/swiftlang/swift-evolution/blob/main/proposals/0525-rawspan-safe-loading-api.md&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/d72kXJ/dJMb8RkfOpK/yKKBP6NU9Fy5j8GEglADA1/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600,https://scrap.kakaocdn.net/dn/GsVnz/dJMb9g5or29/BGBkCE5R8dUNpI5VE5m5BK/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;swift-evolution/proposals/0525-rawspan-safe-loading-api.md at main &amp;middot; swiftlang/swift-evolution&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;This maintains proposals for changes and user-visible enhancements to the Swift Programming Language. - swiftlang/swift-evolution&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;github.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;</description>
      <category>Swift</category>
      <category>rawspan</category>
      <category>safe loading</category>
      <category>SE-0525</category>
      <category>SWIFT</category>
      <author>GREEN.1229</author>
      <guid isPermaLink="true">https://green1229.tistory.com/630</guid>
      <comments>https://green1229.tistory.com/630#entry630comment</comments>
      <pubDate>Sun, 26 Jul 2026 09:25:47 +0900</pubDate>
    </item>
    <item>
      <title>[SE-0532] Optional noncopyable improvements and generalizations</title>
      <link>https://green1229.tistory.com/629</link>
      <description>&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;안녕하세요. &lt;span style=&quot;color: #409d00;&quot;&gt;&lt;b&gt;그린&lt;/b&gt;&lt;/span&gt;입니다  &lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;이번 포스팅에서는 &lt;span style=&quot;background-color: #9feec3;&quot;&gt;&lt;b&gt;SE-0532 &amp;mdash; Optional noncopyable 개선 및 일반화&lt;/b&gt;&lt;/span&gt;에 대해 정리해보겠습니다  &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;12313.001.jpeg&quot; data-origin-width=&quot;400&quot; data-origin-height=&quot;400&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/beTn2H/dJMcaccNloH/VWFh2ipFVLu7KUxK67ZMzk/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/beTn2H/dJMcaccNloH/VWFh2ipFVLu7KUxK67ZMzk/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/beTn2H/dJMcaccNloH/VWFh2ipFVLu7KUxK67ZMzk/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbeTn2H%2FdJMcaccNloH%2FVWFh2ipFVLu7KUxK67ZMzk%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;400&quot; height=&quot;400&quot; data-filename=&quot;12313.001.jpeg&quot; data-origin-width=&quot;400&quot; data-origin-height=&quot;400&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h2 style=&quot;border-left: 4px solid #3a8c28; padding-left: 12px; margin-top: 32px;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;Intro&lt;/span&gt;&lt;/b&gt;&lt;/h2&gt;
&lt;div style=&quot;background: #f2f8ee; border-radius: 10px; padding: 16px 20px; margin: 16px 0;&quot;&gt;
&lt;p style=&quot;margin: 4px 0;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;Proposal:&lt;/b&gt; SE-0532&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;margin: 4px 0;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;Author:&lt;/b&gt; Alejandro Alonso&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;margin: 4px 0;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;Review Manager:&lt;/b&gt; John McCall&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;margin: 4px 0;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;Status:&lt;/b&gt; Accepted&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;margin: 4px 0;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;Implementation:&lt;/b&gt; swiftlang/swift#88505&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;h2 style=&quot;border-left: 4px solid #3a8c28; padding-left: 12px; margin-top: 32px;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;Motivation&lt;/span&gt;&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;Swift 6.0에서 표준 라이브러리 일부가 noncopyable 값을 저장할 수 있도록 일반화된 이후&lt;/b&gt;(SE-0437), &lt;b&gt;noncopyable optional을 다루는 일은 꽤 번거로웠습니다.&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;optional 내부 값을 살짝 들여다보고 싶은 것뿐인데, borrow만 하고 싶을 때도 마땅한 방법이 없었거든요. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;아래 코드를 볼까요?&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;/blockquote&gt;
&lt;pre class=&quot;stylus&quot; style=&quot;background: #1e1e1e; color: #d4d4d4; padding: 16px; border-radius: 8px; overflow: auto;&quot;&gt;&lt;code&gt;if let payload = optional {
  
}

foo(optional) // error: use after consume!&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;다행히 &lt;a href=&quot;https://github.com/swiftlang/swift-evolution/blob/main/proposals/0432-noncopyable-switch.md&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;noncopyable switch&lt;/a&gt;를 쓰면 optional의 내용을 borrow하도록 제어 흐름을 만들 수 있습니다.&lt;/span&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;swift&quot; style=&quot;background: #1e1e1e; color: #d4d4d4; padding: 16px; border-radius: 8px; overflow: auto;&quot;&gt;&lt;code&gt;switch optional {
case .some(let wrapped):
  // wrapped는 borrow된 상태

default:
  break
}

foo(optional) // ok&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;하지만 &lt;code&gt;if let&lt;/code&gt;이나 &lt;code&gt;guard let&lt;/code&gt;에 익숙한 사람이라면 이 switch 문이 그리 직관적이진 않죠  &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;값을 consume하지 않고 mutate만 하고 싶은 경우도 마찬가지예요. &lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;단순한 프로퍼티 변경이나 mutating 메서드 호출 정도는 &lt;code&gt;?.&lt;/code&gt; 체이닝으로 충분하지만, payload를 조건부로 &lt;code&gt;inout&lt;/code&gt; 함수에 넘기고 싶다면 이렇게 써야 합니다.&lt;/span&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;isbl&quot; style=&quot;background: #1e1e1e; color: #d4d4d4; padding: 16px; border-radius: 8px; overflow: auto;&quot;&gt;&lt;code&gt;if someStruct.x != nil {
  foo(&amp;amp;someStruct.x!)
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;혹은 switch로 consume한 뒤 다시 초기화하는, 더 장황하고 직관적이지 않은 방식을 써야 하죠.&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;angelscript&quot; style=&quot;background: #1e1e1e; color: #d4d4d4; padding: 16px; border-radius: 8px; overflow: auto;&quot;&gt;&lt;code&gt;func foo(_: inout NoncopyableString) {}

func bar(_ x: inout NoncopyableString?) {
  switch consume x {
  case .some(var string):
    foo(&amp;amp;string)
    x = consume string

  default:
    x = nil
  }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;여기에 더해 &lt;code&gt;map&lt;/code&gt;, &lt;code&gt;flatMap&lt;/code&gt;, &lt;code&gt;unsafelyUnwrapped&lt;/code&gt; 같은 &lt;code&gt;Optional&lt;/code&gt; API들도 noncopyable 래핑 타입에는 지원되지 않아서, 이런 코드를 매번 switch 문으로 직접 풀어써야 했습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 style=&quot;border-left: 4px solid #3a8c28; padding-left: 12px; margin-top: 32px;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;Proposed Solution&lt;/span&gt;&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;code&gt;Optional&lt;/code&gt;에 새로운 프로퍼티 두 개, &lt;code&gt;ref&lt;/code&gt;와 &lt;code&gt;mutableRef&lt;/code&gt;를 추가합니다. &lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;이 프로퍼티들은 내부 payload가 있으면 그 참조를, 없으면 &lt;code&gt;nil&lt;/code&gt;을 돌려줍니다.&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;pre class=&quot;swift&quot; style=&quot;background: #1e1e1e; color: #d4d4d4; padding: 16px; border-radius: 8px; overflow: auto;&quot;&gt;&lt;code&gt;func bar(_ x: borrowing SomeNoncopyable) {
  ...
}

if let payload = optional.ref {
  bar(payload.value) // 'bar'는 'borrowing Wrapped'를 전달받음
}

foo(optional) // ok&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&quot;angelscript&quot; style=&quot;background: #1e1e1e; color: #d4d4d4; padding: 16px; border-radius: 8px; overflow: auto;&quot;&gt;&lt;code&gt;func baz(_ x: inout SomeNoncopyable) {
  ...
}

if var payload = optional.mutableRef {
  baz(&amp;amp;payload.value) // 'baz'가 payload를 그 자리에서 mutate 가능!
}

foo(optional) // ok&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;이 두 프로퍼티 덕분에 &lt;b&gt;optional의 소유권을 가져오지 않고도 내부 값에 조건부로 접근하는 관용적인 방법&lt;/b&gt;이 생겼습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;더불어 아래 세 메서드도 noncopyable / nonescapable 래핑 타입을 지원하도록 일반화됩니다.&lt;/span&gt;&lt;/blockquote&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;code&gt;map&lt;/code&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;code&gt;flatMap&lt;/code&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;code&gt;unsafelyUnwrapped&lt;/code&gt;&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;vim&quot; style=&quot;background: #1e1e1e; color: #d4d4d4; padding: 16px; border-radius: 8px; overflow: auto;&quot;&gt;&lt;code&gt;let optAtomicInt: Optional&amp;lt;Atomic&amp;gt; = ...
let optInt: Optional = optAtomicInt.map {
  $0.load(ordering: .relaxed)
}

let optInlineArray: Optional&amp;lt;[0 of Atomic]&amp;gt; = []
let optInt2: Optional = optInlineArray.flatMap {
  $0.isEmpty ? nil : $0[0].load(ordering: .relaxed)
}

let optMutex: Optional&amp;lt;Mutex&amp;gt; = ...
let mutex: Mutex = optMutex.unsafelyUnwrapped
optMutex?.withLock { ... } // error: use of 'optMutex' after consume&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;마지막으로 &lt;code&gt;Optional.put()&lt;/code&gt;이라는 편의 API도 추가돼요!&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;아래처럼 &lt;code&gt;!&lt;/code&gt;로 강제 언래핑하던 패턴을 생각해볼게요.&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;lasso&quot; style=&quot;background: #1e1e1e; color: #d4d4d4; padding: 16px; border-radius: 8px; overflow: auto;&quot;&gt;&lt;code&gt;struct Cache: ~Copyable {
  var opt: UniqueArray?
}

var cache = Cache()
var items: UniqueArray = fooBar()
cache.opt = items

let newItem = await retrieveNewItem()
cache.opt!.append(newItem)&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;border-left: 4px solid #3a8c28; background: #f2f8ee; padding: 8px 16px; margin: 16px 0;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;이미 값이 있다는 걸 알고 있는 상황이라 &lt;code&gt;!&lt;/code&gt;가 사실 불필요하고, inline되지 않는 함수를 거치는 경우엔 컴파일러가 최적화해서 없애주지도 못해요.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;code&gt;put()&lt;/code&gt;은 새 값을 넣어주면서 그 payload에 대한 direct mutable reference를 바로 돌려줍니다.&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;lasso&quot; style=&quot;background: #1e1e1e; color: #d4d4d4; padding: 16px; border-radius: 8px; overflow: auto;&quot;&gt;&lt;code&gt;struct Cache: ~Copyable {
  var opt: UniqueArray?
}

var cache = Cache()
let items: UniqueArray = fooBar()
var itemsRef = cache.opt.put(items)

let newItem = await retrieveNewItem()
itemsRef.value.append(newItem)&lt;/code&gt;&lt;/pre&gt;
&lt;h2 style=&quot;border-left: 4px solid #3a8c28; padding-left: 12px; margin-top: 32px;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;Detailed Design&lt;/span&gt;&lt;/b&gt;&lt;/h2&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;ref와 mutableRef&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;/blockquote&gt;
&lt;pre class=&quot;swift&quot; style=&quot;background: #1e1e1e; color: #d4d4d4; padding: 16px; border-radius: 8px; overflow: auto;&quot;&gt;&lt;code&gt;extension Optional where Wrapped: ~Copyable &amp;amp; ~Escapable {
  /// optional 안에 payload가 있으면 그에 대한 borrow된 참조를 반환합니다.
  public var ref: Ref? {
    @lifetime(borrow self)
    get
  }
}

extension Optional where Wrapped: ~Copyable {
  /// optional 안에 payload가 있으면 그에 대한 mutable 참조를 반환합니다.
  public var mutableRef: MutableRef? {
    @lifetime(&amp;amp;self)
    mutating get
  }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;개념적으로 &lt;b&gt;이 프로퍼티들은 optional과 그 payload의 소유권을 옮기는 역할을 해요. &lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;code&gt;ref&lt;/code&gt;를 호출하려면 최소한 &lt;code&gt;borrowing Optional&amp;lt;T&amp;gt;&lt;/code&gt;, 즉 &lt;code&gt;Ref&amp;lt;Optional&amp;lt;T&amp;gt;&amp;gt;&lt;/code&gt;가 있어야 하는데, 이 &lt;code&gt;ref&lt;/code&gt;는 그 &lt;code&gt;Ref&amp;lt;Optional&amp;lt;T&amp;gt;&amp;gt;&lt;/code&gt;를 받아 &lt;code&gt;Optional&amp;lt;Ref&amp;lt;T&amp;gt;&amp;gt;&lt;/code&gt;로 만들어줍니다. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;참조를 optional 내부로 옮겨서, 우리가 mutate하거나 consume하거나 독점적으로 접근할 수 있는 owned 값을 돌려받는 셈이죠. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;code&gt;mutableRef&lt;/code&gt;도 마찬가지로 최소 &lt;code&gt;inout Optional&amp;lt;T&amp;gt;&lt;/code&gt;를 받아 owned &lt;code&gt;Optional&amp;lt;MutableRef&amp;lt;T&amp;gt;&amp;gt;&lt;/code&gt; 값으로 바꿔줍니다.&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;put()&lt;/span&gt;&lt;/b&gt;&lt;/h3&gt;
&lt;pre class=&quot;swift&quot; style=&quot;background: #1e1e1e; color: #d4d4d4; padding: 16px; border-radius: 8px; overflow: auto;&quot;&gt;&lt;code&gt;extension Optional where Wrapped: ~Copyable {
  /// optional의 값을 새 값으로 설정하면서, optional 안에 새로 들어간
  /// payload에 대한 mutable 참조를 반환합니다.
  ///
  /// 이미 값이 있었다면 그 값은 destroy됩니다.
  @lifetime(&amp;amp;self)
  public mutating func put(_ new: consuming Wrapped) -&amp;gt; MutableRef
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;unsafelyUnwrapped 일반화&lt;/span&gt;&lt;/b&gt;&lt;/h3&gt;
&lt;pre class=&quot;swift&quot; style=&quot;background: #1e1e1e; color: #d4d4d4; padding: 16px; border-radius: 8px; overflow: auto;&quot;&gt;&lt;code&gt;extension Optional where Wrapped: ~Copyable &amp;amp; ~Escapable {
  public var unsafelyUnwrapped: Wrapped {
    consuming get
  }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;map(), flatMap() 일반화&lt;/span&gt;&lt;/b&gt;&lt;/h3&gt;
&lt;pre class=&quot;swift&quot; style=&quot;background: #1e1e1e; color: #d4d4d4; padding: 16px; border-radius: 8px; overflow: auto;&quot;&gt;&lt;code&gt;extension Optional where Wrapped: ~Copyable &amp;amp; ~Escapable {
  @lifetime(copy self)
  public consuming func map(
    _ transform: (consuming Wrapped) throws(E) -&amp;gt; Result
  ) throws(E) -&amp;gt; Result?

  @lifetime(copy self)
  public consuming func flatMap(
    _ transform: (consuming Wrapped) throws(E) -&amp;gt; Result?
  ) throws(E) -&amp;gt; Result?
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;사실 &lt;a href=&quot;https://github.com/swiftlang/swift-evolution/blob/main/proposals/0437-noncopyable-stdlib-primitives.md#enum-optional&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;SE-0437&lt;/a&gt; 당시에는 이 일반화를 급하게 적용 하고 싶지 않았다고해요.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;noncopyable 값을 다루는 &lt;code&gt;map&lt;/code&gt; / &lt;code&gt;flatMap&lt;/code&gt;에는 사실 세 가지 형태가 있을 수 있거든요. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;optional 전체를 consume해서 owned 값을 클로저에 넘기거나, borrow해서 참조를 넘기거나, mutate해서 &lt;code&gt;inout&lt;/code&gt; 참조를 넘기거나. 셋 다 유용하지만, 전부 &lt;code&gt;map&lt;/code&gt;이라는 이름으로 오버로드하기엔 규칙상 구분할 방법이 없었죠. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;그래서 이번 제안은 &lt;b&gt;이 일반화를 기본적으로 항상 consuming으로 동작하게 만들고, 대신 &lt;code&gt;ref()&lt;/code&gt; / &lt;code&gt;mutableRef()&lt;/code&gt;로 owned optional 값을 먼저 만들어서 나머지 두 형태를 구현&lt;/b&gt;할 수 있게 했습니다.&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;angelscript&quot; style=&quot;background: #1e1e1e; color: #d4d4d4; padding: 16px; border-radius: 8px; overflow: auto;&quot;&gt;&lt;code&gt;func foo(x: consuming Optional&amp;lt;UniqueArray&amp;gt;) -&amp;gt; Optional {
  x.map {
    $0[0]
  }
}

func bar(x: borrowing Optional&amp;lt;Atomic&amp;gt;) -&amp;gt; Optional {
  x.ref.map { // ok!
    $0.value.load(ordering: .relaxed) &amp;amp;+ 1
  }
}

func baz(x: inout Optional&amp;lt;UniqueArray&amp;gt;) -&amp;gt; Optional {
  x.mutableRef.map {
    // map 하면서 array를 그 자리에서 업데이트
    $0.value.append(123)
    return $0.value.count
  }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;Source Compatibility&lt;/span&gt;&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;code&gt;Optional.ref&lt;/code&gt;, &lt;code&gt;Optional.mutableRef&lt;/code&gt;, &lt;code&gt;Optional.put()&lt;/code&gt;은 새로 추가되는 메서드라 소스 호환성 문제가 없습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;code&gt;map&lt;/code&gt; / &lt;code&gt;flatMap&lt;/code&gt;의 새 오버로드는 기존 함수보다 덜 특수화된 오버로드예요.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;기존에 &lt;code&gt;Optional.map&lt;/code&gt;을 쓰던 코드는 모두 &lt;code&gt;Copyable&lt;/code&gt; wrapped 값을 다루고 있었을 테니, 더 특수화된 기존 &lt;code&gt;Wrapped: Copyable&lt;/code&gt; 오버로드로 그대로 resolve됩니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt; &lt;code&gt;flatMap&lt;/code&gt;도 마찬가지고요. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;그래서 이 일반화된 함수들로 인한 소스 호환성 문제는 없을 것으로 예상합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;code&gt;unsafelyUnwrapped&lt;/code&gt;는 순수한 일반화라 소스 호환성 문제를 일으키지 않습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;ABI Compatibility&lt;/span&gt;&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;code&gt;Optional&lt;/code&gt;에 추가되는 새 메서드들은 표준 라이브러리의 새 API지만 별도 ABI를 필요로 하지 않아요. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;code&gt;map&lt;/code&gt;, &lt;code&gt;flatMap&lt;/code&gt;, &lt;code&gt;unsafelyUnwrapped&lt;/code&gt;의 일반화 역시 새로운 ABI를 추가하거나 기존 ABI를 깨뜨리지 않습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;Implications on Adoption&lt;/span&gt;&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;code&gt;Optional.ref&lt;/code&gt;, &lt;code&gt;Optional.mutableRef&lt;/code&gt;, &lt;code&gt;Optional.put()&lt;/code&gt;은 &lt;code&gt;Ref&lt;/code&gt;와 &lt;code&gt;MutableRef&lt;/code&gt;와 동일한 availability를 가집니다. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;나머지 일반화 부분들은 항상 사용 가능한 것으로 표시됩니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 style=&quot;border-left: 4px solid #3a8c28; padding-left: 12px; margin-top: 32px;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;Future Directions&lt;/span&gt;&lt;/b&gt;&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;Borrow와 inout 바인딩&lt;/span&gt;&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;앞으로 borrow/inout 바인딩을 지원하기로 한다면, 컴파일러가 optional에 대해 &lt;code&gt;if borrow&lt;/code&gt; / &lt;code&gt;if inout&lt;/code&gt; 패턴을 인식해서 조건부로 scope된 접근을 제공하게 할 수도 있어요.&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;stylus&quot; style=&quot;background: #1e1e1e; color: #d4d4d4; padding: 16px; border-radius: 8px; overflow: auto;&quot;&gt;&lt;code&gt;if borrow x = optional {
  
}

foo(optional) // ok&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;만약 이 방향이 &lt;code&gt;ref&lt;/code&gt; / &lt;code&gt;mutableRef&lt;/code&gt; 방식보다 낫다고 판단되면, &lt;code&gt;map&lt;/code&gt;, &lt;code&gt;flatMap&lt;/code&gt;, &lt;code&gt;unsafelyUnwrapped&lt;/code&gt;를 일반화하는 방식도 다시 고민해야 해요. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;더 이상 항상 consuming일 수 없으니까요. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;code&gt;consumingMap&lt;/code&gt;, &lt;code&gt;borrowingMap&lt;/code&gt;, &lt;code&gt;mutatingMap&lt;/code&gt; 등을 따로 만드는 방법도 있지만, API가 계속 늘어나는 건 그리 썩 괜찮은 해법은 아니라고 하네요  &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;Optional: Equatable / Hashable 일반화&lt;/span&gt;&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;SE-0499가 &lt;code&gt;Equatable&lt;/code&gt;, &lt;code&gt;Hashable&lt;/code&gt; 같은 프로토콜을 noncopyable / nonescapable conformer까지 지원하도록 일반화한 만큼, &lt;code&gt;Optional&lt;/code&gt;의 이 conformance들도 suppressed wrapped 타입을 지원하도록 일반화하는 게 당연해 보입니다. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;다만 특정 conformance가 어느 시점에 일반화됐는지 표현할 방법이 없어서, 오래된 ABI 안정 OS에서 실수로 제네릭 &lt;code&gt;==&lt;/code&gt;나 &lt;code&gt;hash(into:)&lt;/code&gt;를 호출해 payload를 copy해버리는 상황은 막아야 해요.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;Ref / MutableRef 자동 역참조&lt;/span&gt;&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;제안된 예시들에서 &lt;code&gt;ref&lt;/code&gt; / &lt;code&gt;mutableRef&lt;/code&gt;로 &lt;code&gt;map&lt;/code&gt;을 쓸 때 &lt;code&gt;.value&lt;/code&gt; 프로퍼티를 명시적으로 접근해야 했죠.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt; 앞으로 &lt;code&gt;Ref&lt;/code&gt;와 &lt;code&gt;MutableRef&lt;/code&gt;에 자동 역참조 기능을 추가해서, 아래처럼 더 편하게 쓸 수 있게 할 수도 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;swift&quot; style=&quot;background: #1e1e1e; color: #d4d4d4; padding: 16px; border-radius: 8px; overflow: auto;&quot;&gt;&lt;code&gt;func bar(x: borrowing Optional&amp;lt;Atomic&amp;gt;) -&amp;gt; Optional {
  x.ref.map { // ok!
    // '.value.'가 더 이상 필요 없음
    $0.load(ordering: .relaxed) &amp;amp;+ 1
  }
}&lt;/code&gt;&lt;/pre&gt;
&lt;h2 style=&quot;border-left: 4px solid #3a8c28; padding-left: 12px; margin-top: 32px;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;Alternatives Considered&lt;/span&gt;&lt;/b&gt;&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;Optional 바인딩의 기본 소유권 방식 변경&lt;/span&gt;&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;이 제안의 동기에서는 &lt;code&gt;ref&lt;/code&gt;, &lt;code&gt;mutableRef&lt;/code&gt; 같은 프로퍼티가 borrowing 버전의 제어 흐름을 위해 필요하다고 설명했어요. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;대신 &lt;code&gt;if let&lt;/code&gt; 같은 optional 바인딩의 기본 소유권 방식을 borrowing으로 바꾸는 방법도 있었습니다. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;하지만 이건 optional 바인딩이 consuming이라고 가정하는 기존 코드에 대해 source-breaking 변경이 됩니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;Optional.borrow()와 Optional.mutate() 메서드&lt;/span&gt;&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;이전 리비전에서는 &lt;code&gt;ref&lt;/code&gt;, &lt;code&gt;mutableRef&lt;/code&gt; 대신 &lt;code&gt;borrow()&lt;/code&gt;, &lt;code&gt;mutate()&lt;/code&gt;라는 메서드 이름을 제안했었어요. 하지만 &lt;code&gt;InlineArray&lt;/code&gt;나 &lt;code&gt;UniqueArray&lt;/code&gt; 같은 타입의 &lt;code&gt;span&lt;/code&gt;, &lt;code&gt;mutableSpan&lt;/code&gt; 프로퍼티와 결을 맞추고 싶어서 최종적으로는 프로퍼티 형태가 더 선호됐습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 style=&quot;border-left: 4px solid #3a8c28; padding-left: 12px; margin-top: 32px;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;Conclusion&lt;/span&gt;&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;noncopyable optional을 다루는 게 이번 제안으로 한결 편해질 것 같아요  &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;지금까지는 내부 값을 살짝 들여다보기만 해도 consume 에러를 피하려고 switch 문을 직접 작성해야 했는데, &lt;code&gt;ref&lt;/code&gt; / &lt;code&gt;mutableRef&lt;/code&gt; 덕분에 &lt;code&gt;if let&lt;/code&gt;처럼 자연스럽게 접근할 수 있게 됐습니다. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;code&gt;put()&lt;/code&gt;도 강제 언래핑을 줄여주는 실용적인 추가고요. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;code&gt;map&lt;/code&gt;, &lt;code&gt;flatMap&lt;/code&gt;, &lt;code&gt;unsafelyUnwrapped&lt;/code&gt;까지 일반화되면서, noncopyable 타입을 다루는 코드가 Copyable 타입을 다룰 때와 비슷한 느낌으로 작성할 수 있을 것 같습니다  &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 style=&quot;border-left: 4px solid #3a8c28; padding-left: 12px; margin-top: 32px;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;References&lt;/span&gt;&lt;/b&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;figure id=&quot;og_1784377874630&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;object&quot; data-og-title=&quot;swift-evolution/proposals/0532-optional-noncopyable-improvements.md at main &amp;middot; swiftlang/swift-evolution&quot; data-og-description=&quot;This maintains proposals for changes and user-visible enhancements to the Swift Programming Language. - swiftlang/swift-evolution&quot; data-og-host=&quot;github.com&quot; data-og-source-url=&quot;https://github.com/swiftlang/swift-evolution/blob/main/proposals/0532-optional-noncopyable-improvements.md&quot; data-og-url=&quot;https://github.com/swiftlang/swift-evolution/blob/main/proposals/0532-optional-noncopyable-improvements.md&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/QejmU/dJMb9c9KuFW/Zuc9qRuObCGBRVnm80VTe0/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600,https://scrap.kakaocdn.net/dn/bssUwH/dJMb8Z3Eglv/iRJuxZnP2VNw5CbC9PJJGk/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600&quot;&gt;&lt;a href=&quot;https://github.com/swiftlang/swift-evolution/blob/main/proposals/0532-optional-noncopyable-improvements.md&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://github.com/swiftlang/swift-evolution/blob/main/proposals/0532-optional-noncopyable-improvements.md&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/QejmU/dJMb9c9KuFW/Zuc9qRuObCGBRVnm80VTe0/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600,https://scrap.kakaocdn.net/dn/bssUwH/dJMb8Z3Eglv/iRJuxZnP2VNw5CbC9PJJGk/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;swift-evolution/proposals/0532-optional-noncopyable-improvements.md at main &amp;middot; swiftlang/swift-evolution&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;This maintains proposals for changes and user-visible enhancements to the Swift Programming Language. - swiftlang/swift-evolution&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;github.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;</description>
      <category>Swift</category>
      <category>noncopyable</category>
      <category>SE-0532</category>
      <category>SWIFT</category>
      <author>GREEN.1229</author>
      <guid isPermaLink="true">https://green1229.tistory.com/629</guid>
      <comments>https://green1229.tistory.com/629#entry629comment</comments>
      <pubDate>Sat, 18 Jul 2026 21:33:05 +0900</pubDate>
    </item>
    <item>
      <title>What's new in SwiftData (feat. WWDC 2026)</title>
      <link>https://green1229.tistory.com/628</link>
      <description>&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;안녕하세요. &lt;span style=&quot;color: #409d00;&quot;&gt;&lt;b&gt;그린&lt;/b&gt;&lt;/span&gt;입니다  &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;이번 포스팅에서는 &lt;span style=&quot;background-color: #9feec3;&quot;&gt;&lt;b&gt;WWDC 2026에서 나온 SwiftData 부분에서 업데이트 사항들에 대해 살펴보고 정리&lt;/b&gt;&lt;/span&gt;해보겠습니다  &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;Sectioning your fetches&lt;/span&gt;&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;먼저 SwiftData에서 섹션별로 데이터를 가져오는 방법을 보겠습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2026-07-12 오후 6.14.41.png&quot; data-origin-width=&quot;827&quot; data-origin-height=&quot;428&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bhimzf/dJMcacX6ugh/K04KMnaVySXZgzEKWjOKP0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bhimzf/dJMcacX6ugh/K04KMnaVySXZgzEKWjOKP0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bhimzf/dJMcacX6ugh/K04KMnaVySXZgzEKWjOKP0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbhimzf%2FdJMcacX6ugh%2FK04KMnaVySXZgzEKWjOKP0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;827&quot; height=&quot;428&quot; data-filename=&quot;스크린샷 2026-07-12 오후 6.14.41.png&quot; data-origin-width=&quot;827&quot; data-origin-height=&quot;428&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;이제는 이렇게 쿼리에서 옵션을 주어 그룹별로 묶을 수 있어요.&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;각 섹션에선 ID 속성이 있고 이걸 활용하게 됩니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;Using custom types&lt;/span&gt;&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;모델에 커스텀 타입을 저장하는 기능 향상을 살펴볼께요.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;SwiftData는 로드될 때 모델에 대한 스키마를 자동으로 생성합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;스키마는 모델 클래스와 엔티티간 매핑을 정의하죠.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;대부분의 타입에선 이게 자동으로 작동해요.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;그렇지만 모델 매크로로 어노테이션 되지 않은 클래스는 자동으로 검사할 수 없기에 SwiftData는 스키마 생성에 실패합니다  &lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;만약 그렇다고 구현체에 접근할 수 없을 수 있잖아요?&lt;/span&gt;&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2026-07-12 오후 6.18.23.png&quot; data-origin-width=&quot;643&quot; data-origin-height=&quot;389&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ttsoG/dJMcafAxHil/BOSilGDEXAsPPEHw16zjek/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ttsoG/dJMcafAxHil/BOSilGDEXAsPPEHw16zjek/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ttsoG/dJMcafAxHil/BOSilGDEXAsPPEHw16zjek/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FttsoG%2FdJMcafAxHil%2FBOSilGDEXAsPPEHw16zjek%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;643&quot; height=&quot;389&quot; data-filename=&quot;스크린샷 2026-07-12 오후 6.18.23.png&quot; data-origin-width=&quot;643&quot; data-origin-height=&quot;389&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;그런 경우 이렇게 어트리뷰트 codable을 사용하여 주면 해결됩니다.&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;이 속성은 SwiftData에 타입의 인코딩된 표현을 저장하도록 알려주는 역할을 합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;타입에 대한 스키마를 추론하는 대신에요.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;다만 염두해둬야할게 있는데, codable 속성의 내용은 SwiftData에 불투명합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;이는 Predicate에서 결과를 필터링하는데 사용할 수 없음을 나타내요.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;또는 정렬도 사용할 수 없어요.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;또한 codable 형태가 변경되면 속성을 추가하거나 제거하는 경우 마이그레이션이 트리거되지 않아요.&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;이 점을 주의해야 합니다!&lt;/span&gt;&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;Codable 속성 사용은 SwiftData가 기본적으로 지원하지 않는 타입을 저장하는 탈출구라고 생각하면 좋습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;직접 정의했다면 왠만해선 Codable 사용을 금해야 합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;Observing data stores&lt;/span&gt;&lt;/b&gt;&lt;/h2&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;스토어를 모니터링하고 데이터 변경 시 알림 받는 방법을 살펴볼께요.&lt;/span&gt;&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2026-07-12 오후 6.22.41.png&quot; data-origin-width=&quot;475&quot; data-origin-height=&quot;347&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cTvIGj/dJMcaalCTfH/lzBtKCSoBE76r8uRfKaVIK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cTvIGj/dJMcaalCTfH/lzBtKCSoBE76r8uRfKaVIK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cTvIGj/dJMcaalCTfH/lzBtKCSoBE76r8uRfKaVIK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcTvIGj%2FdJMcaalCTfH%2FlzBtKCSoBE76r8uRfKaVIK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;475&quot; height=&quot;347&quot; data-filename=&quot;스크린샷 2026-07-12 오후 6.22.41.png&quot; data-origin-width=&quot;475&quot; data-origin-height=&quot;347&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;SwiftUI에서는 이렇게 데이터가 변경되면 뷰가 쿼리의 새로운 결과를 반영해 다시 렌더링합니다.&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;만약 SwiftUI가 아닌 부분은 어떨까요?&lt;/span&gt;&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;이걸 위해 이번 2027 릴리즈에선 ResultsObserver를 도입했습니다.&lt;/span&gt;&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2026-07-12 오후 6.24.50.png&quot; data-origin-width=&quot;335&quot; data-origin-height=&quot;338&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/BkiZg/dJMb991pUis/lOGVAUVqMUgQPB8k33gHz0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/BkiZg/dJMb991pUis/lOGVAUVqMUgQPB8k33gHz0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/BkiZg/dJMb991pUis/lOGVAUVqMUgQPB8k33gHz0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FBkiZg%2FdJMb991pUis%2FlOGVAUVqMUgQPB8k33gHz0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;335&quot; height=&quot;338&quot; data-filename=&quot;스크린샷 2026-07-12 오후 6.24.50.png&quot; data-origin-width=&quot;335&quot; data-origin-height=&quot;338&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;SwiftUI 쿼리처럼 데이터 가져오고 관찰하고 반영시키는 Swift Observation을 사용해요.&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2026-07-12 오후 6.25.59.png&quot; data-origin-width=&quot;760&quot; data-origin-height=&quot;346&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b2yfnH/dJMcaiKJjnj/mkFHPOGWflAZKsNGSfDMK1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b2yfnH/dJMcaiKJjnj/mkFHPOGWflAZKsNGSfDMK1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b2yfnH/dJMcaiKJjnj/mkFHPOGWflAZKsNGSfDMK1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb2yfnH%2FdJMcaiKJjnj%2FmkFHPOGWflAZKsNGSfDMK1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;760&quot; height=&quot;346&quot; data-filename=&quot;스크린샷 2026-07-12 오후 6.25.59.png&quot; data-origin-width=&quot;760&quot; data-origin-height=&quot;346&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;이런식으로 사용될 수 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;&lt;b&gt;withContinuousObservation은 ObservationTracking 토큰을 반환&lt;/b&gt;합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;이 &lt;b&gt;토큰이 관찰의 수명을 정의&lt;/b&gt;하죠.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;여기서 더 나아가 이번 업데이트에서는 히스토리 관찰도 지원해줍니다.&lt;/span&gt;&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2026-07-12 오후 6.30.26.png&quot; data-origin-width=&quot;394&quot; data-origin-height=&quot;305&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dfHSrK/dJMcahymdti/kXjRP0UithYrkaAwFRRAsk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dfHSrK/dJMcahymdti/kXjRP0UithYrkaAwFRRAsk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dfHSrK/dJMcahymdti/kXjRP0UithYrkaAwFRRAsk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdfHSrK%2FdJMcahymdti%2FkXjRP0UithYrkaAwFRRAsk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;394&quot; height=&quot;305&quot; data-filename=&quot;스크린샷 2026-07-12 오후 6.30.26.png&quot; data-origin-width=&quot;394&quot; data-origin-height=&quot;305&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;데이터 스토어가 저장될 때마다 SwiftData는 히스토리 트랜잭션을 기록합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;여기에는 변경된 내용에 대한 정보가 포함됩니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;그리고 변경이 어디서 왔는지 조차도 포함되죠.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;히스토리에서 트랜잭션을 고유하게 식별하는 토큰도 있습니다.&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;ModelContext.fetchHistory() 이 API와 토큰을 함께 사용할 수 있어요.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2026-07-12 오후 6.32.27.png&quot; data-origin-width=&quot;887&quot; data-origin-height=&quot;282&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/XR4c2/dJMcagzpXq5/HWOKwsRkZ6kpSXKFhfVf6k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/XR4c2/dJMcagzpXq5/HWOKwsRkZ6kpSXKFhfVf6k/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/XR4c2/dJMcagzpXq5/HWOKwsRkZ6kpSXKFhfVf6k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FXR4c2%2FdJMcagzpXq5%2FHWOKwsRkZ6kpSXKFhfVf6k%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;887&quot; height=&quot;282&quot; data-filename=&quot;스크린샷 2026-07-12 오후 6.32.27.png&quot; data-origin-width=&quot;887&quot; data-origin-height=&quot;282&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;HistoryObserver는 스토어의 변경 사항에 쉽게 반응할 수 있게 해줍니다.&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;지속적 히스토리 관찰과 새로운 트랜잭션 추가 시 코드가 반응하도록 해주죠.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;특정 종류의 변경만 관찰하고 대응하고 싶다면 물론 HistoryObserver를 사용해 모델 타입과 트랜잭션 작성자로 필터링할 수 있어요.&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;외부 서버와 같은 다른 시스템과 연동 시 효과적이죠.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;외부와 연동하는 예시를 볼까요?&lt;/span&gt;&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2026-07-12 오후 6.33.27.png&quot; data-origin-width=&quot;833&quot; data-origin-height=&quot;425&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/UNBRA/dJMcacX6usv/iFX1WrACfWzECbaNqu62Gk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/UNBRA/dJMcacX6usv/iFX1WrACfWzECbaNqu62Gk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/UNBRA/dJMcacX6usv/iFX1WrACfWzECbaNqu62Gk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FUNBRA%2FdJMcacX6usv%2FiFX1WrACfWzECbaNqu62Gk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;833&quot; height=&quot;425&quot; data-filename=&quot;스크린샷 2026-07-12 오후 6.33.27.png&quot; data-origin-width=&quot;833&quot; data-origin-height=&quot;425&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;이렇게 간단히 코드로 나타내서 사용할 수 있습니다.&lt;/span&gt;&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;&lt;b&gt;References&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;figure id=&quot;og_1783848834990&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;SwiftData의 새로운 기능 - WWDC26 - 비디오 - Apple Developer&quot; data-og-description=&quot;SwiftData의 최신 개선 사항을 확인하세요. Codable을 사용하여 맞춤형 및 타사 유형을 유지하는 방법과 가져온 데이터를 SwiftUI 앱의 섹션으로 그룹화하는 방법을 안내합니다. 또한 ModelResultsObserver와&quot; data-og-host=&quot;developer.apple.com&quot; data-og-source-url=&quot;https://developer.apple.com/kr/videos/play/wwdc2026/274/&quot; data-og-url=&quot;https://developer.apple.com/kr/videos/play/wwdc2026/274/&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/c55bAO/dJMb8RR33zg/erWRND5znnmRHJeEdxsxaK/img.jpg?width=500&amp;amp;height=282&amp;amp;face=0_0_500_282,https://scrap.kakaocdn.net/dn/HJkIe/dJMb8WeLUTG/t1q0uDdC6kJJcb5kKQPkh0/img.jpg?width=1800&amp;amp;height=1012&amp;amp;face=0_0_1800_1012&quot;&gt;&lt;a href=&quot;https://developer.apple.com/kr/videos/play/wwdc2026/274/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://developer.apple.com/kr/videos/play/wwdc2026/274/&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/c55bAO/dJMb8RR33zg/erWRND5znnmRHJeEdxsxaK/img.jpg?width=500&amp;amp;height=282&amp;amp;face=0_0_500_282,https://scrap.kakaocdn.net/dn/HJkIe/dJMb8WeLUTG/t1q0uDdC6kJJcb5kKQPkh0/img.jpg?width=1800&amp;amp;height=1012&amp;amp;face=0_0_1800_1012');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;SwiftData의 새로운 기능 - WWDC26 - 비디오 - Apple Developer&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;SwiftData의 최신 개선 사항을 확인하세요. Codable을 사용하여 맞춤형 및 타사 유형을 유지하는 방법과 가져온 데이터를 SwiftUI 앱의 섹션으로 그룹화하는 방법을 안내합니다. 또한 ModelResultsObserver와&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;developer.apple.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;</description>
      <category>SwiftData</category>
      <category>ios</category>
      <category>SWIFT</category>
      <category>SwiftData</category>
      <category>WWDC 2026</category>
      <author>GREEN.1229</author>
      <guid isPermaLink="true">https://green1229.tistory.com/628</guid>
      <comments>https://green1229.tistory.com/628#entry628comment</comments>
      <pubDate>Sun, 12 Jul 2026 18:36:37 +0900</pubDate>
    </item>
    <item>
      <title>느즈막히 올려보는 쿠팡에서의 회고 (feat. 또다른 시작)</title>
      <link>https://green1229.tistory.com/627</link>
      <description>&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;안녕하세요. &lt;span style=&quot;color: #409d00;&quot;&gt;&lt;b&gt;그린&lt;/b&gt;&lt;/span&gt;입니다  &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;이번 포스팅에서는 &lt;b&gt;사실 기술적인 부분보다 회고를&lt;/b&gt; 하나 해볼까 합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #000000;&quot;&gt;제가 근 1년 6개월 정도 근무했던 쿠팡을 떠나게 되었는데, 사실 쿠팡 입사 직후와 3개월쯤 되었을때 각각 쿠팡 이직기라던지 쿠팡에서의 일상 회고를 해보려 했는데, 일과 개인적인 바쁨에 치여 결국 쿠팡을 나올때 이렇게 회고를 올려보네요  &lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;그래서, 이번 회고는 역시나 무근본 무형식으로 그냥 두서없이 한번 적어보려고 합니다  &lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1066&quot; data-origin-height=&quot;1448&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/W5hQx/dJMcacwYj5X/JYRjfnXGirwek85iJeDvE1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/W5hQx/dJMcacwYj5X/JYRjfnXGirwek85iJeDvE1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/W5hQx/dJMcacwYj5X/JYRjfnXGirwek85iJeDvE1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FW5hQx%2FdJMcacwYj5X%2FJYRjfnXGirwek85iJeDvE1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;440&quot; height=&quot;598&quot; data-origin-width=&quot;1066&quot; data-origin-height=&quot;1448&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/blockquote&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #000000;&quot;&gt;쿠팡 입사&lt;/span&gt;&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;25년 2월에 쿠팡으로 이직을 하게 됩니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #000000;&quot;&gt;왜 이직했는지 그냥 지금와서 간단히 정리해보면, 정말 글로벌 서비스를 하는것과 글로벌 회사에서 일하는것을 경험해보고 싶었어요.&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;이전까지는 iOS 개발자 1인으로 내 할일을 다하는것에 초점이였다면 앞으로의 성장을 생각했을때 그걸 넘어서 정말 일을 잘하는 사람이 되고 싶었어요.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;개발에 국한된게 아니라 일을 잘하는 사람이요.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #000000;&quot;&gt;그랬을때 좀 더 큰 대규모의 서비스를 경험해보면서 다국가 인종과 일하는 경험 이 두가지가 쿠팡을 지원하고 입사를 하게된 가장 큰 이유였습니다  &lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;그래서 쿠팡에서 쿠팡이츠라는 O2O 배달 앱 서비스의 시니어 iOS 엔지니어로 근무를 하게 됩니다.&lt;/span&gt;&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;그럼 쿠팡에서의 1년 6개월을 돌이켜봤을때 어떤것을 해왔고 어떤걸 배웠는지 한번 정리해볼까해요.&lt;/span&gt;&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #000000;&quot;&gt;Life in Coupang&lt;/span&gt;&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;우선 일은 굉장히 굉장히 하드워킹이긴 했습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;그렇다고 밤낮이 없는 삶, 원양어선 그런건 아니였어요.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;그냥 주어진 시간에 정말 1초도 쉬지 않고 일하면 다 끝날 수 있는 그런 정도..?&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #000000;&quot;&gt;제가 맡은 TF는 주로 Ads TF였습니다.&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;배달 앱의 특성 상 배달이나 플랫폼 수수료 같은걸로는 정부 규제도 있고 단가가 그렇게 크지 않아 사실상 사업적인 부분에서 큰 이익이 되지 않는다고 생각해요.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;그렇기에 또 다른 비지니스적인 부분을 고려할때 광고를 무시할 수 없습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #000000;&quot;&gt;점포나 메뉴 광고가 주인데 어떤 부분에 배치하거나 어떤 시간대에 어떤걸 배치하면 이 점포를 가장 극대화되어서 CPC나 CPS를 올릴 수 있을지 같이 고민하고 여러 실험을 해보는 그런 TF입니다.&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;광고라는 도메인이 익숙치도 않고 처음 해보는거였지만 그만큼 재밌었어요.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;직접적으로 주간으로 광고를 통해 얼마나 많은 매출에 기여했는지 확연하게 눈에 보일 수 있었기에 더 동기부여가 되었습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #000000;&quot;&gt;또한, 광고 TF말고도 두루 경험해봤던것도 큰 기억으로 남아요.&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;핵심인 음식 배달과 요즘 밀고 있는 쇼핑(마트나 편의점, 꽃집 등등 - 푸드가 아닌 모든것) 그리고 고객들의 VOC나 편의성을 개선하기 위한 CRM TF 등 한 팀에 정말 다양한 TF가 로테이션으로 돌아가며 일을 하게 되는데 이 모든것의 비지니스 태스크를 한번씩은 해본것 같습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;그러다보니 자연스레 다양한 코드들을 보게되고 깊게 이해하게 되었어요.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-size=&quot;size18&quot; data-ke-style=&quot;style1&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;이렇게 거시적으로 볼 수 있는 비지니스적인 일은 어떻게 했는지에 대해 간단히 회고를 해본다면 이제는 팀에 대한 회고를 해볼까해요.&lt;/span&gt;&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #000000;&quot;&gt;사실상 가장 많이 짧다면 짧은 시간에 성장할 수 있게 된 원동력이 바로 소속된 iOS 팀이였습니다.&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #000000;&quot;&gt;솔직하게 지금까지 나름 다양한 회사도 다녀보고 여러 동아리도 해보고 컨퍼런스도 다녀보면서 교류해봤지만 개발자 개개인의 역량으로는 쿠팡이 가장 월등하다고 느꼈어요.&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;쿠팡의 채용 과정이 정말 복잡하고 난이도가 큰 편이라 더 그런지는 몰라도 개발자의 능력은 어느 회사보다도 뛰어나다고 확신할 수 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #000000;&quot;&gt;그렇기에 같이 부딪히며 토론하고 때론 설전도 벌이면서 일을 하면서 성장한것 같아요  &lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;쿠팡에서 일하기 전까지의 저를 돌이켜보면 iOS 개발 맡은거 능히 해낼 수 있는 개발자라고 말할 수 있다면, 여기서 배운건 그건 당연히 해야되는거고 그거 말고도 너가 더 뭘할 수 있는데?에 대한 푸시가 많고 그걸 잘 끌어올려줄 매니저와 팀원들이 존재했습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;너가 1인분 하는건 당연히 시니어 개발자가 아니라 주니어 개발자여도 당연히 해야되는거고, 그걸 넘어서 시니어 개발자라면 팀에 어떤 영향을 미칠 수 있는지 고민하고 iOS 뿐만 아니라 더 스펙트럼을 넓혀서 안드로이드, 웹을 포함한 프론트 그리고 백엔드까지 비지니스 스펙을 받으면 고려해서 테크적인 리드를 할 줄 알아야 하며 그런 부분을 하드 트레이닝을 많이 했던것 같아요.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #000000;&quot;&gt;그래서 일감이 주어지면 항상 어떻게 개발해야하지? 라는 생각보다 이게 정말 괜찮은 실험인지 이 실험을 성공시키기 위해서 각 파트에서 어떤 노력을 기울이면 좋을지 그리고 그게 제일 효과적인 방법일지를 고민하게 저의 일을 접근하는 방식 자체가 많이 변화한것 같아요.&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;그전에는 iOS 앱 개발 부분에서만 고민했다면 이제는 백엔드와의 트레이드오프도 생각해보고 좀 더 크로스 플랫폼에서 일하기 적절한 방법과 그리고 기능 개발 대비 어느정도 인력 코스트가 들어가는지 그런것들까지 고민하고 제안을 하게 되는 개발자로 성장했어요.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #000000;&quot;&gt;그리고 그건 제가 원하지 않아도 쿠팡에서 일을 하면 자연스럽게 요구되는 역량이고 그렇게 변하게 만들어주더라구요  &lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;그리고 팀적으로도 &lt;b&gt;매주 테크 미팅을 통해 서로 기술을 공유하고 새로 맡은 비지니스 일감이 있다면 항상 먼저 테크 디자인을 한 후 공유해서 더 나은 방향이 있는지를 모바일 팀 자체적으로 더 체크&lt;/b&gt;를 합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;이렇게 꼼꼼하고 다양한 의견을 듣다보면 자연스럽게 시야도 넓어지게 되더라구요.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #000000;&quot;&gt;쿠팡에서는 이렇게 정말 많은 미팅과 룰과 일이 존재해요.&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;그러다보니 눈코 뜰 새가 없는건 사실이지만 어떻게 보면 가장 이상적인 시스템이라곤 생각이 되더라구요.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;그 시스템에서 번아웃이 안오고 버티는게 힘든것 뿐이지만 회사적인 측면으로만 보면 합리적이고 비지니스가 성장할 수 있는 시스템이란 생각이 많이 듭니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #000000;&quot;&gt;그리고 또 많이 성장했던 부분은 바로 영어일것 같아요.&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;사실 영어를 잘하지 못했고 지금도 그렇지만 하나 달라진건 자신감인것 같아요.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;회사에선 공식적으로 한국어로 일하는것 자체가 없어요.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;공용 언어가 영어이기에 슬랙, 위키 등등 모든것이 영어죠.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;그리고 미팅도 통역이 제공되는 경우도 있지만 기본이 영어입니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;그러다보니 사실 살려면 해야됐었어요.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;저도 처음에 입사해서 &quot;아 이거 일보다 커뮤니케이션이 영어라 따라갈 수 있나?&quot; 싶었어요.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;그래서 슬랙도 그렇고 번역기에 번역하고 하고 싶은 말도 번역해서 떠듬떠듬 치고 그랬죠.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;그런데 이게 일상에 녹아드니 별다른 영어 공부를 하지 않아도 자연스럽게 익숙해지기 마련이더라구요.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;그 전에는 예를 들어 &quot;이거 확인해주실 수 있나요?&quot; 라는걸 영어로 말해야된다 생각하면 머릿속에서 문법부터 생각하고 완성한 다음 이게 진짜 맞나 고민하고 그런것들때문에 영어가 입 밖으로 더 안나왔던것 같아요.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;그런데 이제는 일단 문법이 다 맞지 않고 그렇더라도 이 바쁜 일상에서 우선 커뮤니케이션이 우선이고 먼저 말해야된다는 압박이 있다보니 자연스레 &quot;Could you check this?&quot;와 같이 나오게 되더라구요.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #000000;&quot;&gt;물론 더 좋은 표현도 있고 하겠지만 배운 한가지가 자신감이라 했잖아요?&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #000000;&quot;&gt;이 자신감은 확실히 익힌것 같아요.&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #000000;&quot;&gt;이제 말로 표현하고 문장으로 쓰는게 내가 틀렸다 하더라도 두렵지가 않게 되었습니다.&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;그리고 앞서 계속 말했지만 팀원들 정말 훌륭하고 귀중한 팀원들 그리고 타 팀의 교류하는 사람들 모두 좋은 인프라를 쌓을 수 있어 감사했어요.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #000000;&quot;&gt;일이 빡센만큼 전우애가 더 많이 생기게 되는 쿠팡이였어요.&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;나간다니 이런 것까지 해주는 팀원들인데 어떻게 잊을 수 있을까 싶어요.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;IMG_9900.JPG&quot; data-origin-width=&quot;2252&quot; data-origin-height=&quot;4000&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cdbwwc/dJMcadbtC6A/PhGnBgVv7EdPn1DY5EqCVk/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cdbwwc/dJMcadbtC6A/PhGnBgVv7EdPn1DY5EqCVk/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cdbwwc/dJMcadbtC6A/PhGnBgVv7EdPn1DY5EqCVk/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fcdbwwc%2FdJMcadbtC6A%2FPhGnBgVv7EdPn1DY5EqCVk%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;321&quot; height=&quot;570&quot; data-filename=&quot;IMG_9900.JPG&quot; data-origin-width=&quot;2252&quot; data-origin-height=&quot;4000&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;그래서 정리해보면 쿠팡에서 생활하면서 성장한 부분은 이렇습니다.&lt;/span&gt;&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #000000;&quot;&gt;1️⃣ 기술적인 견고함과 더 넓게 바라볼 수 있는 시야&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #000000;&quot;&gt;2️⃣ 개인 혼자만이 아니라 팀 전체에 영향을 미칠 수 있는 사고&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #000000;&quot;&gt;3️⃣ 영어 의사소통&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #000000;&quot;&gt;4️⃣ 정말 비지니스적으로 어떤것들이 도움되는지에 대한 고민&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;이 외에도 서버 드리븐적인 설계, 대쉬보드들을 구축해서 모니터링을 강화하는 방법, 장애 대응, AI 오너로써 팀을 이끌어본 경험 등등 기술적으로나 팀에 영향을 주는 부분으로나 정말 다양한 포인트들이 있지만 그거까지 쓰면 한도 끝도 없을것 같아 우선 쿠팡에서의 라이프는 간략하게 이정도로 마칠까 합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;그럼 가장 중요한 포인트인데 왜 쿠팡을 떠나는지에 대해 간단히 정리하고 마쳐보려고 해요.&lt;/span&gt;&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #000000;&quot;&gt;Why am I leaving Coupang?&lt;/span&gt;&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #000000;&quot;&gt;당연히 이직이 쉬운 선택도 아니고 또 새로운 도전을 하는것은 더더욱 쉬운 선택이 아닙니다.&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;그리고 그런 결정을 하기까지에는 정말 큰것부터 정말 사소한것까지 많은 복합적인 부분이 상호작용 할거에요.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;여기선 몇가지 핵심적인 이유를 전해볼까해요.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;우선, 쿠팡이 다니기에 좋지 않은 회사다 라는것은 전혀 아닙니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;일이 힘들 순 있지만 그거때문에 이직하는건 도피라고 생각해요.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #000000;&quot;&gt;어딜가나 힘든건 있기 마련이고 일이 바쁘다고 나가는건 근로자의 덕목이 아니라 생각하기 때문이죠.&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #000000;&quot;&gt;1️⃣ 더 넓은 글로벌 서비스&lt;/span&gt;&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;가장 큰것중 하나는 바로 이 항목이에요.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;쿠팡이츠를 개발하면서 현재는 한국과 일본을 타겟으로 서비스하고 있는데, 일본을 고려해서 글로벌한 서비스를 구축하고 운영하다 보니 정말 더 많은 나라들 나아가서 대륙들을 타겟으로 하는 더 큰 글로벌 서비스들이 궁금해졌어요.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;그리고 글로벌 서비스를 해보니 재미가 있더라구요.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #000000;&quot;&gt;같은 앱이지만 각 문화 환경에 따라 원하는 화면과 폰트 배치들이 다르다는것도 세삼 느끼게 되면서 뭔가 리전을 바꿀때마다 여행하는 느낌이 들었어요.&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;직간접적으로 그 나라를 체험해보는거죠.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;그래서 이를 충족하는 서비스를 해보고 싶다는 생각이 컸습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #000000;&quot;&gt;2️⃣ 컨텐츠 플랫폼에 대한 니즈&lt;/span&gt;&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;그리고 저는 사실 개발자를 처음 해올때부터 사용자들이 몰두할 수 있는 컨텐츠 플랫폼을 해보고 싶었어요.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #000000;&quot;&gt;지금까지는 주로 커머스, O2O와 같은 사용자들이 앱에 들어와서 빠르게 확인하고 구매하고 나가는 그런 동선으로 비지니스를 이끄는 서비스였어요.&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #000000;&quot;&gt;그러다보니 한 화면에서 애니메이션이나 더 심미적인 부분보다는 탐색 플로우나 결제 플로우에서 로직과 빠른 구매가 더 중요해지더라구요.&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;그래서 한편으로는 그런 부분들을 많이 다룰 수 없었어요.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;여담이지만 저는 KWDC 2023에서 SwiftUI 애니메이션 관련 세션을 발표할 정도로 심&lt;b&gt;미적인것과 사용자의 더 아름다운 경험을 구현하는걸 원하고 좋아하는 개발자&lt;/b&gt;에요.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;그래서 그런 부분을 채울 수 있는 컨텐츠 플랫폼 서비스를 꼭 해보고 싶었어요.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;그럼 왜 여태까지 그런거 안했냐? 라고 한다면 안한게 아니라 못했던거라고 할 수 있어요  &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;사실 알려진 컨텐츠 플랫폼 앱이 몇개 되지도 않지만 제가 원한다고 내일부터 그 회사에 들어가서 해볼 수 있는건 아니잖아요..?&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;무튼 그래서 컨텐츠 플랫폼을 향한 저의 개발자로서의 니즈가 이직의 큰 몫을 했습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #000000;&quot;&gt;3️⃣ 거리&lt;/span&gt;&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #000000;&quot;&gt;마지막으로 누군가한테 사소할 수도 있지만 저한테 큰 부분이였던건 회사와의 거리였어요.&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;사실 쿠팡에 입사한것도 처음엔 하이브리드로 재택이 존재했기에 공고나 계약도 그렇게 진행되었어요.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;그래서 선릉까지 출퇴근하는게 매일이 아니니 부담스럽지 않고 현실적으로 가능했죠.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;그런데 작년부터 풀출근으로 근무제도가 변경되면서 이는 적지 않은 부담으로 다가왔어요.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;(물론 모든 쿠팡 부서가 그런건 아니고 근무제도는 조직장에 따라 모두 부바부입니다.)&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;그러다보니 출퇴근 하는데 드는 시간, 체력소모, 비용 그런것들까지 트레이드 오프 되는것을 생각해볼때 쿠팡이 큰 메리트가 되지 않는단 생각이 문득 들더라구요.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;그래서 사소할 수 있지만 저한텐 어떻게 보면 심리적으로 가장 큰 부분이였어요.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #000000;&quot;&gt;이런 대표적인 이유 + 말하진 않았지만 더 많은 이유들이 상호작용하여 이직을 결심하게 되었습니다.&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;(혹시 말하지 않았지만 더 많인 이유들이 궁금하시다면 연락주세요 ㅋㅋㅋ)&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;그래서 이번엔 어딜 가는데?&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;/blockquote&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;이번에는 1과 2그리고 3번의 이직 이유들을 충족할 수 있는 곳으로 가게되었어요.&lt;/span&gt;&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1000&quot; data-origin-height=&quot;1000&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/crY72j/dJMcadvLNul/U9CuFDvM4fKZeLkjCwtvKK/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/crY72j/dJMcadvLNul/U9CuFDvM4fKZeLkjCwtvKK/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/crY72j/dJMcadvLNul/U9CuFDvM4fKZeLkjCwtvKK/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcrY72j%2FdJMcadvLNul%2FU9CuFDvM4fKZeLkjCwtvKK%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;291&quot; height=&quot;291&quot; data-origin-width=&quot;1000&quot; data-origin-height=&quot;1000&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #000000;&quot;&gt;네이버웹툰에서 글로벌 웹툰 iOS 앱 개발에 기여하게 되었습니다.&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;아직 출근전이고 이 글이 나가는 시점에서 한 주 후 첫출근을 하게 될 예정이라 떨리네요 ☺️&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;인터뷰들을 진행하며 제가 더 다른 성장하고 싶은 포인트와 해소하고 싶은 포인트들을 네이버 웹툰에서 더 다양하게 해볼 수 있을것 같아 많은 기대가 됩니다!&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;아 그리고 현재 쿠팡에서 해당 제 포지션의 채용이 열려있어요!&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;관심 있으시거나 궁금한 부분이 있으신 분은 언제든 편하게 연락주시면 제가 아는선에서 알려드리고 도와드릴께요  &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;제가 장담하건데 꼭 다녀봐야할 회사라고 생각합니다.&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;figure id=&quot;og_1783315930824&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;Sr Mobile Engineer (Eats iOS)&quot; data-og-description=&quot;쿠팡이츠(Coupang Eats)는 쿠팡의 음식 배달 서비스이자,대한민국에서 빠르게 성장하고 있는 배달 서비스입니다. 2019년 국내 배달 업계에 혜성처럼 등장한 쿠팡이츠는 2024년 &amp;lsquo;무제한 무료배달&amp;rsquo;로&quot; data-og-host=&quot;www.coupang.jobs&quot; data-og-source-url=&quot;https://www.coupang.jobs/kr/jobs/7991999/sr-mobile-engineer-eats-ios/?gh_jid=7991999&quot; data-og-url=&quot;https://www.coupang.jobs/kr/jobs/7991999/sr-mobile-engineer-eats-ios/&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/cyqOMW/dJMb8UH0H9e/RHjnMaYoA85KVEBn3iQ4CK/img.png?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630&quot;&gt;&lt;a href=&quot;https://www.coupang.jobs/kr/jobs/7991999/sr-mobile-engineer-eats-ios/?gh_jid=7991999&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://www.coupang.jobs/kr/jobs/7991999/sr-mobile-engineer-eats-ios/?gh_jid=7991999&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/cyqOMW/dJMb8UH0H9e/RHjnMaYoA85KVEBn3iQ4CK/img.png?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;Sr Mobile Engineer (Eats iOS)&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;쿠팡이츠(Coupang Eats)는 쿠팡의 음식 배달 서비스이자,대한민국에서 빠르게 성장하고 있는 배달 서비스입니다. 2019년 국내 배달 업계에 혜성처럼 등장한 쿠팡이츠는 2024년 &amp;lsquo;무제한 무료배달&amp;rsquo;로&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;www.coupang.jobs&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;또 어떤 재밌는 일들이 벌어지고 경험하게 될지 모르겠지만, 언젠가 또 좋은 회고로 찾아오도록 하겠습니다  &lt;/span&gt;&lt;/blockquote&gt;</description>
      <category>회고</category>
      <author>GREEN.1229</author>
      <guid isPermaLink="true">https://green1229.tistory.com/627</guid>
      <comments>https://green1229.tistory.com/627#entry627comment</comments>
      <pubDate>Mon, 6 Jul 2026 13:39:50 +0900</pubDate>
    </item>
  </channel>
</rss>