iOS개발자 앨런입니다.
https://www.youtube.com/@allen_ios
제가 공부하면서 겪었던 시행착오를 쉽게 풀어내어
지식을 공유할 수있는 개발자가 되고싶습니다.
쉬운 주제로 빠른 시간 안에 겉핥기 식으로 쉽게만 가르치는 강의를 만드는 것에는 관심이 없습니다.
그런 강의는 얼마든지 빠르게 찍어내듯 만들 수 있겠지만, 결국 "좋은 개발자로 성장"하는 것은 그만큼 이론적인 기반의 밑거름이 탄탄해야 한다고 믿고 있기 때문입니다.
쉬운 강의보다는, 좋은 개발자(끝임없이 성장할 수 있는 개발자)가 되기 위해
반드시 알아야 하는 어려운 내용까지를 최대한 쉽게, 그리고 직관적으로 알려드리는 것.
그래서 제가 아닌 여러분 스스로 고민/생각할 수 있는 밑거름을 만들어 드리는 것을 저의 강의 목표로 삼고 있습니다.
저 스스로도 내일은 더 좋은 개발자가 되자는 모토를 가지고 있는 만큼
제가 고민 했던 내용들을 깊이있게 전달 드리고 싶습니다.
👇🏻문의는 아래의 이메일로 주시면 됩니다.
we.love.code.allen@gmail.com
언어: Swift(스위프트), Python, Java, C#
강의
수강평
- 앨런 Swift Concurrency for Swift 6 (Part-1)
- 앨런 Swift Concurrency for Swift 6 (Part-1)
- 앨런 Swift Concurrency for Swift 6 (Part-1)
- 앨런 Swift Concurrency for Swift 6 (Part-1)
- 앨런 Swift Concurrency for Swift 6 (Part-1)
게시글
질문&답변
수강 기간 연장 신청 요청드립니다.
안녕하세요 moo 님. 죄송한데 제가 연장 처리를 해드리고 싶어도, B2B결제(회사에서 비즈니스 계정)으로 결제 하신 것이라.. 제가 연장을 해드릴 수 있는 권한이 없습니다.ㅠㅠ(제 쪽에서 처리할 수 있는 기능 자체가 없습니다.) 인프런에 직접 문의해보셔야할 것 같습니다. (강사가 3개월 연장 해줄 수 있으면 해주고 싶다고 했다고.. 요 링크나 캡처를 가지고 직접 문의해보세요..ㅠㅠ)(인프런에서 수동으로 처리되어야 하는 부분인 것 같습니다.) 감사합니다. :)
- 0
- 2
- 22
질문&답변
Task 클로저에서 weak self 미사용에 대해 질문드립니다!
안녕하세요 범수님! (이런 질문을 주실때는 코드 예시가 있었으면, 더 좋았을 것 같다는 생각이 들긴하네요. 코드 예시가 없으면, 서로의 말의 의도가 다를 수도 있으니까요..ㅠㅠ)무튼 그럼에도.. 질문주신 바를 최대한 의도에 맞게 답변을 드려보면..'self가 해제된 시점'에서 'weak self 사용'한 'GCD 클로저'에서는 내부 동작이 실행되지 않을 것 같은데요 ===> 아니요. 일반적으로 self가 nil이 되니.. nil 상태로 동작을 합니다. (클로저는 self가 nil 인 상태로.. 클로저의 중괄호가 끝날때까지 동작을 합니다. 그렇기 때문에 일반적으로 중간에 guard let self else 이런 코드를 넣어, 동작을 안 시킬 수는 있겠죠. self가 nil인 경우 guard 문에서 종료가 될테니까요.)'self가 해제된 시점'에서 'weak self 미사용'한 'Task 클로저'에서는 내부 동작의 실행이 보장될 것 같은데 ===> self가 해제된 시점이라고 가정하는게 의미가 있을까요??ㅠㅠ 어차피 Task 클로저는 [weak self]를 사용하지 않아도, 중괄호 끝까지 self를 유지시키다가 자연스럽게 중괄호가 끝날때 self를 해제시킨다는 것인데요? self가 해제가 되었다면, 처음부터 Task 클로저를 실행하지도 못할 상황에 더 가깝지 않을까(?)란 생각이 듭니다.. (제 생각엔 가정이 이상하긴 하지만, Task가 동작을 시작했다면, 중괄호가 끝날때까지 동작은 하겠죠.)(제가... 질문 주신 의도를 잘 모르겠습니다...ㅠㅠ 제가 질문 주신 의도를 잘 못 파악 한 것이라면 다시 질문 부탁드립니다.) 무튼, 위에서 말씀드린 대로 [weak self]를 GCD클로저도 일단은 self가 nil인 상태로 동작을 하게 되니.. 두 경우다 클로저가 종료 시점까지 동작을 하게 됩니다. 고맙습니다. :)
- 0
- 1
- 49
질문&답변
안녕하세요. 액터 홉핑 관련 질문드립니다.
네 안녕하세요!질문 주신 내용에 대한 이해가.. 바로 앞의 질문하고 연관이 조금 있어서, 바로 앞의 질문/답변도 읽어보시면 좋을 것 같고요!(우선 참고적으로 말씀드리면, 플레이그라운드에서 실험하는게 크게 의미가 없을 수도 있습니다. 플레이그라운드의 경우 내부적으로 2개의 쓰레드만 사용되도록 설정이 되어 있어요. 그래서 강의 중간에 액터 프로젝트를 사용해서 (Instruments를 사용해서 설명드리고 있으니) 홉핑 문제를 다뤘던 부분을 잘 생각해보시면 좋을 것 같기도 합니다.)(첫번째 질문)액터 홉핑이 일어나게 되면, 액터에 내장되어 있는 실행자(executor)가 전환되고, 이는 곧 액터에서 실행되는 스레드의 묶음이 바뀌는 것이니, (실행 컨텍스트는 물론) 스레드 컨텍스트 스위칭이 일어날 수 있다라고 보는 게 맞을까요?네. CPU(쓰레드)가 바뀌는 것이지 (정확하게 표현하자면 컨텍스트 스위칭이라고 표현하기는 조금 애매한데) (바로 앞 질문 답변에서 말씀드렸듯이 실행하는 CPU(쓰레드)가 바뀌는 개념하고, 컨텍스트 스위칭과는 조금 달라서요.) 무튼 (동일한 실행자를 커스텀으로 설정한게 아니라면) CPU(쓰레드)가 바뀌는 것은 맞습니다. 중간에 제가 보여드린 프로젝트의 Instrument에서 확인가능하세요!(여기서 참고적으로 말씀드릴 수 있는 것은, 단순히 프린트를 찍어보는 것하고, 실제 오래걸리는 작업들로 실험하는 것은 많이 달라질 수 있습니다. 왜냐면, 짧게 짧게 끝나는 단순 프린트 같은 작업들은.. 쓰레드를 이동하지 않는 것처럼 보일 수도 있습니다.)(두번째 질문)메인 액터-일반 액터 간 홉핑은 메인 스레드와 협력형 스레드 풀 간의 전환이니, 실행 컨텍스트와 스레드 컨텍스트 전환이 무조건 일어나는 게 맞을까요?네. CPU(쓰레드)가 바뀌어요. 위와 동일한 질문으로 보여서. 위의 답변과 비슷합니다.(세번째 질문)일반 액터-일반 액터 간 홉핑은 모두 Swift 동시성이 기본으로 제공해주는 직렬 실행자(serial executor)에서 실행되고, 이 직렬 실행자는 협력형 스레드 풀에서 실행되는 것이니, 실행 컨텍스트 전환은 일어날 수 있어도 스레드 컨텍스트 스위칭은 일어날 수도 있고, 일어나지 않을수도 있다고 보는 게 맞을까요?(일단은 쓰레드 컨텍스트 스위칭이라고 표현하셨는데, 저는 CPU(쓰레드) 전환이라고 표현할께요. 어떤 의미로 말씀하셨는지 모르지만.. 정확하게 표현하기 위해서요.)뭐 그렇게 생각하실 수도 있지만.. 기본적으로 일어날 수도 있고/일어날 수 있지 않을 수도 있다라고 생각하는 것보다는 이런 경우 이론적으로 무조건 일어난다고 보는 것이 맞다고 생각합니다. 왜냐면, CPU(쓰레드) 간의 전환은 운영체제가 알아서 해주는 부분인데, 예를 들어 액터A가 (2, 3, 4번 쓰레드를 쓸수도 있고) 액터B가 (4, 5, 6번 쓰레드를 쓸 수도 있는데) (일부러 4번 쓰레드는 같이 쓸 수도 있다고 가정해서 말씀드리고 있음..) 근데, 그런식으로 접근하면.. 우리가 통제할 수 있는 부분이 아니죠. (실행할때마다 달라질 수 있습니다.)그렇다면, 만약에 우리가 퍼포먼스를 엄청 중요시 하는 프로젝트를 만들어야 한다고 가정해보면.. 전환이 안 일어날 수도 있는 가능성이 개선을 하지 말아야 할까요? 저는 아니라고 생각합니다. 경우에 따라서 달라지는 경우의 수를 따지는게 아니라, 무조건 액터 홉핑(CPU(쓰레드) 전환)이 일어난다고 생각하고 프로젝트를 개선해야 한다고 봅니다.(질문 주신 것들보니.. 제 생각에는, 너무 디테일하게 접근하고 계시는 것 같은데) 액터의 경우도 그림 그리신 것처럼 생각하는 것보다는 그냥 1개의 쓰레드라고 "이론적으로" 접근하는게 더 맞다고 생각해요.(내부적으로 CPU(쓰레드) 전환은... Swift Concurrency와 운영체제가 알아서 해주는 부분이니까요.) 감사합니다. 이해가 안되시는 부분이 있으시면 다시 질문 부탁드립니다. 감사합니다. :)
- 0
- 1
- 51
질문&답변
업데이트 예정 강의 공개 일정이 궁금합니다.
아, 경구 님 죄송합니다 ! 제가 너무 정신이 없어서 신경을 못쓰고 있었네요! 강의로 올릴지 글로 올릴지 고민 중이었는데, 4월 11일까지 업로드 해놓도록 하겠습니다 !ㅠ 고맙습니다 :)
- 1
- 1
- 64
질문&답변
29강 async let 작업 취소 부분 질문
네 안녕하세요 joey !제가 CASE 1 , CASE 2 에서 말씀드리려고 하는 포인트는, async let의 암시적취소에서는 코드 순서의 배치가.. 암시적 취소 전파에 중요한 영향을 미칠 수 있다는 점에 대해서 말씀드리려고 하는 거예요 !암시적 취소: 하나의 자식 작업에서 에러가 발생했을 때, 나머지 다른 자식 작업에 에러를 전파하는 경우예를 들어 아래처럼 튜플로 구현하실때, image3를 가장 먼저 배치 시키시면, (아무리 튜플이라고 하더라도) 튜플의 첫번째 요소를 가장 먼저 기다린 후에.. 그 다음 image3 -> image1 -> image2 -> image4 -> image5 로 넘어갑니다.(여기서 image3가 에러를 발생시키고 가장 일찍 종료가 되는 경우임)let fetchedImages = try await (images3, image1, image2, image4, image5)따라서, 위처럼 구현하시는 것은 아래의 코드와 순서가 완전히 동일합니다. (동일하게 동작할 수 밖에 없습니다. image3가 가장 먼저 배치되어 있고, 코드는 "순서대로"만 기다리게(동작하게) 됩니다.)let fetchedImage3 = try await image3 let fetchedImage1 = try await image1 let fetchedImage2 = try await image2 let fetchedImage4 = try await image4 let fetchedImage5 = try await image5 따라서 순서를 동일하게 배치하면 완전히 동작이 똑같은 순서대로 동작하겠지만.. 예를 들어 튜플 순서를 아래처럼 1 -> 2 -> 3 -> 4 -> 5 로 배치시키시면, 동작이 달라질 수 있다는 것을 설명드리기 위한 예제입니다.let fetchedImages = try await (images1, image2, image3, image4, image5) 이점을 잘 생각해보시면 좋을 것 같아요! 고맙습니다. :)
- 0
- 1
- 69
질문&답변
재개될 때 스레드 변경시 왜 컨텍스트 스위칭이 발생하지 않는 건가요?
네 안녕하세요 Joy!네 협력적 쓰레드풀 방식은 CPU와 쓰레드가 1대1 관계로 바뀌었기 때문에, CPU코어 이상의 쓰레드를 생성하지 않는 방식이예요. (정확하게, 프로세스(process)라는 건 한개의 앱의 실행을 의미하기 때문에, CPU가 프로세스는 아닙니다. 여러개의 쓰레드 동작을 합쳐서.. 1개의 앱의 실행 == 프로세스(실행 중인 프로그램의 인스턴스)라고 하는 겁니다.)따라서, 프로세스 내부에서 일어나던 컨텍스트 스위칭이라고 표현하는 건 옳지 않다고 생각하고, CPU에서 다른 쓰레드로 전환하는 과정이 맞을 것 같아요.(정확하게는 컨텍스트 스위칭은 2개의 개념에서 일어날 수 있는데.. (1) 프로세스(앱) 간의 컨텍스트 스위칭 (2) 하나의 프로세스(실행되고 있는 앱 한개) 안에서의 컨텍스트 스위칭이 일어날 수 있지만, 저는.. 하나의 앱의 실행 과정에 대해서 설명드리고 있는 것이기 때문에.. 제가 설명드리는 부분은 (2)번 내용에 대해서 말씀드리는 것입니다.)(그래서 프로세스 내부에서 일어나는 컨텍스트 스위칭이 없어진게 아니라, CPU에서 다른 쓰레드로 전환하는 과정이 없어졌다고 표현하는 것이 정확하다고 말씀드리는 거예요.)헷갈리시는 부분에 대해서1. 왜 다른 쓰레드에서 재개가 되는 작업이 컨텍스트 스위칭이 일어나지 않는 건지108페이지 그림을 잘 생각해보시면 좋을 것 같아요. 기존의 방식은 1개의 (운영 체제의 소프트웨어적인) 쓰레드 내부에서 아래 그림처럼 컨텍스트 스위칭이 일어났었는데, 이제 컨텍스트 스위칭이 일어나지 않는 방식으로 바뀌었습니다.(사진)따라서, 비동기 함수가 멈췄다가 다른 쓰레드에서 재개가 되는 것이.. 컨텍스트 스위칭이 일어나지 않는 개념하고는 다른 개념이예요. 예를 들어서, 비동기(async) 함수가 2번 쓰레드에서 실행되다가 3번쓰레드에서 재개가 되더라도..(사진)이건 컨텍스트 스위칭이 아닙니다. (뒤에 메모리 구조(4강 내용)에서 일어나는 일까지 보시면.. 더 정확하게 이해가 되시겠지만..) 이건 실제로 실행하던 CPU코어가 바뀌었을 뿐이지.. 1개의 CPU가 자기가 실행중인 쓰레드를 전환한 개념은 아닙니다. (따라서, 이부분을 다시 한번 잘 생각해 보시면 좋을 것 같아요.)2. CPU당 하나씩 쓰레드를 가지게 되면 최대 동시 실행할 수 있는 앱은 CPU코어수 만큼으로 제한되는지그건아닙니다. 약간 헷갈리고 계신 것 같은데.. 8코어 CPU라고 하면.. 하나의 앱이 실행되는 동안 최대 8개의 쓰레드를 사용할 수있다는 뜻인데.. 그렇다고 하더라도.. 다른 앱들도.. iOS 운영체제에 의해 백그라운드 쓰레드에서 동작하고 있을 수 있습니다. (그리고 갯수가 꼭 그렇게 코어 만큼으로 제한되지는 않습니다.)그냥 조금 쉬운 예를 들어서 생각해보면.. 아이폰에서 조금 무거운(?) 하나의 앱을 실행시키셨다고 가정을 해보면.. 그 무거운 앱이 아무리 빡세게 돌아가더라도 8개의 쓰레드(CPU)를 풀로 사용하고 있는 경우는 거의 없습니다. 그러면 예를 들어, 6개의 쓰레드(CPU)를 풀로 사용하고, 2개의 쓰레드(CPU)를 조금 널럴하게 사용하고 있다면.. 운영체제는 알아서 널럴하게 사용중인 2개의 쓰레드(CPU)를 사용해서 백그라운드에서 멜론(?) 같은 앱을 돌릴 수 있습니다. (운영체제가 알아서 하는 부분이기도 하죠.)이런 것처럼.. CPU(쓰레드)가 8개 이니 무조건 8개의 앱만 돌아가는 것은 아니고, 운영체제는 지금 실행되고 있는 (Foreground에서 돌아가고 있는) 앱은 더 많은 CPU를 활용해서 일처리 하는 것일 뿐인 것이고, 백그라운드에서 돌아가고 있는 앱에는 조금 제한된 CPU 등의 자원을 할당해서 돌아가게 만들 수 있습니다. 따라서, 동시에 실행 가능한 앱의 수는.. CPU 코어 수와는 직접적인 관련이 없고, 8코어(CPU) 기기에서도 10개의 앱을 "실행 중"으로 유지할 수 있습니다. (잘 생각해보시면.. 꼭 iOS 뿐만아니라 그게 macOS라고 하더라도 어차피 인간이 집중해서 처리하는 앱은 일단은 (Foreground에 있는) 한개일 것이기 때문에.. 운영체제가 지금 집중적으로 사용하지 않는 앱은.. CPU등의 리소스를 덜 할당한다.. (아니면 잠시 멈춰놓는다?) 이런 개념으로 생각하시면 됩니다.)결론적으로 , Swift Concurrency의 협력적 스레드 풀 모델은 (컨텍스트 스위칭을 하지 않아) 1개의 CPU의 효율성을 향상시키는 것이지, 시스템(운영체제) 전체에서 실행 가능한 앱의 수를 제한하는 것은 아닙니다.
- 0
- 2
- 106
질문&답변
Task를 함수 내부에서 사용했을 때 값의 변화를 예상하는 법
네 안녕하세요 영균 님! 일단 제가 보기엔 지금 2가지 포인트를 잘 못 짚고 계시는 것 같은데요,(1) Task.yield()의 의미를 정확하게 이해하기 위해 다시 생각해 보시면 좋을 것 같습니다. (8강 22분 전후의 내용 다시 보시는 것도 추천을 드리고요.)원칙적으로 async/await 의 비동기(async) 함수는.. 함수 자체가 운영체제에 오래 걸리는 일처리 동안.. 자기가 사용하는 쓰레드를 양보하게 됩니다. 따라서, 기본적으로 yield( )를 사용하지 않아도 비동기 함수는 양보하게 되어 있습니다.(따라서 보통은 yield( ) 메서드를 사용 하실 필요가 없지만) 어떤 오래 걸리는 일처리 전후로 쓰레드를 양보하고 싶다면.. 선택적으로 사용할 수도 있는 것입니다. 예를 들어..func 비동기로오래걸리는함수() async -> Data { await 비동기함수실행() // 비동기적으로 1초 걸린다고 가정 실제오래걸리는함수1실행() // 동기적으로 10초 걸린다고 가정 실제오래걸리는함수2실행() // 동기적으로 10초 걸린다고 가정 실제오래걸리는함수3실행() // 동기적으로 10초 걸린다고 가정 await 비동기함수실행() // 비동기적으로 1초 걸린다고 가정 }위의 비동기 함수는 대략 32초걸리는 비동기작업이라고 가정해보겠습니다. (설명을 드리기 위해 일부러 함수1,2,3은 동기작업으로 가정한거예요.) 위의 작업은 최소한 32초 이상이 걸릴 수 밖에 없습니다. 동기작업은 30초가 무조건 걸리고.. 비동기는 최소 2초가 걸릴텐데.. 비동기작업에서는 쓰레드를 양보했다가.. 나중에 재개가 될 수 있으니 (쓰레드 사용에 의해서 내부적으로 멈췄다가.. 재개될 수 있으니) 2초보다 더 걸릴 수 있겠죠.(그래도 중간의 동기작업은 한번 일을 시작하면 쓰레드를 양보하는 일이 없을테니, 무조건 30초가.. 스트레이트로 일어날 수 밖에 없습니다. 중간에 양보 시점이 아예 없습니다.) 그러면... 위와 같은 상황에서 30초가 스트레이트로 걸리는 일은.. 너무 오래 걸리는 일이니까..func 비동기로오래걸리는함수() async -> Data { await 비동기함수실행() // 비동기적으로 1초 걸린다고 가정 실제오래걸리는함수1실행() // 동기적으로 10초 걸린다고 가정 try await Task.yield() 실제오래걸리는함수2실행() // 동기적으로 10초 걸린다고 가정 try await Task.yield() 실제오래걸리는함수3실행() // 동기적으로 10초 걸린다고 가정 await 비동기함수실행() // 비동기적으로 1초 걸린다고 가정 }중간에 쓰레드를 양보하면.. 10초씩마다.. 혹시나 다른 일처리가 있다면.. 쓰레드를 양보하는 코드를 넣어주면.. 스트레이트로 30초가 일어나는 일처리를 막을 수 있다는 뜻입니다.(위의 예제를 잘 생각해보시고 다시 질문주세요. 지금 yield메서드의 사용 예시가 잘못 되었습니다.) (2) 아래 Task 함수를 잘 못 설계하셨어요.func dispatch(_ event: Event) { // 2번쓰레드에서 시작 Task { // 3번 쓰레드에서 작업 생성 switch event { case .buttonTapped: count += await fetch() } } }위와 같이 하시면, 예를 들어 dispatch 동기함수가 2번쓰레드에서 작업을 시작해도, 작업을 생성하면서 3번 쓰레드에서 일을 시키고 기다리지 않습니다. Task는 작업을 생성하는 것이기도 하지만.. DispatchQueue.global().async { } 와 비슷하게 일을 시작 시키고 (작업을 생성하고) Task { } 내부의 일이 끝날때까지 기다리지 않는 코드 입니다.따라서 제가 봤을때.. 원하시는 코드가.. dispatch함수가.. 함수 내부의 작업(Task)이 끝날때까지 기다리길 원하시는 것 같은데.. 예를 들어 아래 처럼 작성 하셔야 합니다.func dispatch(_ event: Event) async { // 2번쓰레드에서 시작 let task = Task { switch event { case .buttonTapped: count += await fetch() } } await task.value // 일이 끝날때까지 기다렸다가.. dispatch함수 종료 가능 }위의 코드 내용이 이해가 안가시면, 작업(Task)의 종료 부분의 내용을 강의에서 천천히 코드를 다시 보셨으면 좋겠습니다. (이런 실수들을 하실까지봐.. 제가 처음부터 작업(Task)에 대해서 설명드릴 때.. task.value에서 작업을 기다리는 방법들도 다 설명드린 것입니다.) 위의 내용들을 천천히 다시 생각 해보시고.. 이해가 안되시는 부분이 있으시면 다시 질문 주세요 ! 고맙습니다. :)
- 0
- 2
- 104
질문&답변
playground에서 상단 실행?아이콘 회전 관련하여...
네 안녕하세요 산마로 님. 플레이그라운드의 경우.. 워낙 오류가 많은 프로그램이라.. 너무 신경쓰시지 않아도 됩니다. 특히나 엑스코드 버전이 업데이트 되는 경우, 더 많은 오류들이 발생되기도 합니다. 저도 잘 안되는 경우(저도 가끔씩 원 아이콘이 돌아갈 때) 엑스코드를 껐다키거나, 맥북을 껐다키기도 합니다. 정확한 원인을 저도 모르겠어요 ^^;그리고 현재는 또 Swift 5 / 6 버전이 과도기 적인 상황이라 아마, 플레이그라운드에 더 오류가 많은 것으로 알고 있어요. 가급적이면, 플레이그라운드에서 안정적인 Swift 5를 사용하시는 것도 방법이겠죠.(사진) 오류가 워낙 많아서.. 집착하지 않으셔도 됩니다..! 고맙습니다 :)
- 0
- 1
- 45
질문&답변
활용앱53강에서 질문있습니다.
네 산마로 님.우리가 프로젝트를 생성할때 처음부터 존재하는 ViewController 파일은.. 그냥 애플이 편하게 만들라고 기본 템플릿 같은 것을 제공해주는 개념이라고 생각하시면 됩니다.따라서, ViewController이름을 LoginViewController라고 바꾸시고, (다만 스토리보드가 기존의 ViewController로 연결이 되어있기 때문에) 이것만 우측의 Identifier Inspector 화면에서 LoginViewController로 다시 선택하시면 돼요!그리고 기본적으로.. 코드 Base로 프로젝트를 만드는 경우, 스토리 보드를 아예 삭제해서 사용하실 수도 있는데.. 그런건..https://storing.tistory.com/43이런 링크를 참고해 보시거나 "xcode 스토리보드 삭제"로 구글링 해보시면 또 많은 자료들을 참고하실 수 있습니다 🙂 고맙습니다 !
- 0
- 2
- 73
질문&답변
Project 명칭 변경방법이 궁금합니다.
네 산마로 님그런건, 구글링을 잘 활용해보시면 좋을 것 같아요 :) https://velog.io/@afg0212/Xcode-Project-Name-%EB%B3%80%EA%B2%BD%ED%95%98%EA%B8%B0이런 블로그글을 참고 부탁드립니다.고맙습니다 !
- 0
- 1
- 48