스트리밍은 대부분의 브라우저와
Developer 앱에서 사용할 수 있습니다.
-
Xcode Playgrounds로 프로토타이핑하기
Xcode Playgrounds로 새로운 코드를 프로토타이핑하여 변경 사항 확인을 위해 프로젝트를 다시 빌드하고 실행해야 하는 수고를 없애 기능 개발의 속도를 올리세요. 여러분의 프로젝트나 패키지에서 플레이그라운드를 사용하여 다양한 시나리오의 코드를 시도해 보고, 복잡한 구조나 사용자 인터페이스 요소와 같은 반환 값을 자세히 살펴보는 방법을 소개하여 기능을 빠르게 반복 테스트하고 프로젝트에 통합할 수 있도록 도와드립니다.
챕터
- 3:00 - Exploring the data model and inspecting UI snapshots
- 14:26 - Becoming familiar with a new package
- 18:07 - Using the Live View
- 22:03 - Running the updated project
리소스
관련 비디오
WWDC20
-
다운로드
♪ ♪
안녕하세요, Dariusz예요 Xcode Playgrounds 팀 엔지니어죠 Xcode Playgrounds의 개선 사항을 통해 프로젝트에서 새 기능을 쉽게 프로토타이핑하는 법을 보여드리죠 Xcode Playgrounds를 통해 작업 흐름을 개선하는 다양한 방법이 있어요 먼저 프로젝트를 다시 빌드하고 실행하는 단계를 건너뛰고 새로운 기능을 프로토타이핑할 수 있으며 코드에 사소한 변경 사항을 적용해 볼 수 있죠 또한 접근하기 어려운 코드를 쉽게 실행할 수 있는데 쇼핑 앱에서 주문 요약을 생성하는 논리를 예로 들 수 있어요 물론 이런 코드는 테스트를 통해 확인해야 하지만 Playgrounds를 개발의 시작점으로 사용하기에 안성맞춤이죠 또한 프로젝트에 새로운 요소를 도입하기 전에 코드를 시험해 볼 수 있는 완벽한 환경이에요
Xcode Playgrounds가 어떻게 제 앱에 도움이 됐는지 보여드리죠 현재 야생 동물 사진을 관리할 수 있는 간단한 앱을 개발 중인데요 현재 제 앱이 제가 찾아서 사진을 찍은 동물 종이 어떤 건지 관리해 주고 있어요 이제 야생 동물 사진과 관련하여 중요한 기능을 추가하려고 하는데 원하는 동물을 찾는 기능이죠
체크리스트 뷰를 위한 새 탭을 넣고 싶은데
이미 뷰를 적용했고 현재 사용자 인터페이스에 만족해요 새마다 체크박스가 있어서 진행 상황을 확인할 수 있죠 하지만 목록의 새가 2,000종이 넘어서 진행한다는 느낌을 못 받을 것 같아요 목록을 줄일 수 있으면 좋겠군요
그러려면 birdsToShow 연산 프로퍼티를 커스텀 ChecklistView에서 수정해야 해요 현재 BirdProvider 타입을 생성할 때 북미만 설정돼 있어서 북미 대륙 전체에서 찾을 수 있는 모든 새를 반환하죠 프로젝트를 다시 빌드하고 실행하는 작업을 피하고 ChecklistView에 가서 변동 사항을 확인하기 위해 Xcode Playgrounds에서 코드를 수정해 볼게요
먼저 프로젝트에 새 Playground를 추가하세요
iOS 앱이니까 iOS 템플릿을 유지할게요 필터에 'Playground'를 입력하고 Blank Playground를 선택하세요
이 경우에는 여러 가지를 테스트한 뒤에 Playground를 제거하여 기본 이름 'MyPlayground'를 유지할게요
Playground의 기본 콘텐츠를 삭제할게요
더 빨리 반복하기 위해 하단의 실행 버튼을 길게 클릭하여 나타나는 메뉴에서 Automatically Run을 선택하죠
이렇게 하면 제가 수정 작업을 멈출 때마다 Playground가 전체 코드를 자동으로 실행해요 프로젝트에 추가된 Playground의 기본 설정이 2개 있는데 Build Active Scheme과 Import App Types예요 Playground를 실행하기 전에 활성화된 스킴의 빌드를 확인하고 앱의 목표 모듈이 자동으로 임포트 됐는지 확인하죠 이렇게 하면 프로젝트에 정의된 타입으로 작업하는 게 훨씬 쉬워져요 이제 인스펙터를 닫고 Playground 공간을 넓힐 수 있죠
먼저 BirdProvider 인스턴스를 선언할 건데 ChecklistView의 birdsToShow 프로퍼티와 같아요
에디터 오른쪽의 결과 사이드바에 따르면 이 선언으로 Playground 결괏값을 생성했죠 이제 인라인 결괏값 토글로 자세한 내용을 볼 수 있어요
인라인 결과에 BirdProvider 인스턴스의 세부 사항과 2개의 프로퍼티가 나타나죠 birds 배열과 제공되는 지역이에요 Xcode 15에는 각 행에 타입 정보 레이블이 있어서 타입에 관한 요약 정보를 보여 주며 행마다 툴팁을 이용하여 세부 사항을 볼 수 있죠
예를 들어 툴팁에 의하면 BirdProvider 타입이 제 앱 모듈에서 나왔으며 region 이넘이 해당 구조체에서 정의됐음을 알려 줘요 이제 배열 행을 확장하여 birds의 세부 사항을 보죠
인라인 결과 뷰와 상호작용하기 시작했더니 Xcode 15가 결괏값을 생산한 소스 코드를 강조해요 이 경우 뷰가 birdProvider 상수에 할당한 값을 표시하죠 이를 통해 표시된 값을 더 쉽게 이해할 수 있어요
배열의 요소를 더 자세히 살펴보죠
region과 birds 배열 프로퍼티의 깔끔한 요약을 봤는데 기본적으로 각 새를 대표하는 행은 배열 인덱스에 관해서만 알려 줘요 커스텀 Bird 타입에 정의된 설명이 없기 때문이죠
이를 개선하기 위해 Bird 타입이 CustomStringConvertible 프로토콜에 컨폼하도록 수정해요 Playground나 Sources 디렉터리에 확장 프로그램을 추가할 수 있죠 두 방식 모두 Playground 범위 내 Bird 타입에만 영향을 주므로 이를 사용하는 다른 영역인 디버거 같은 곳에는 설명이 나오지 않을 거예요 그래서 Bird 타입을 정의하는 확장 프로그램을 파일에 추가하죠
새로운 개념 설명을 통해 각 행에서 새의 일반명과 학명이 나타나요 다시 Playground로 돌아가서 새로운 설명을 확인해 보죠
Playground 자동 실행 모드에서는 다시 열었을 때 Playground가 자동으로 다시 실행돼요 birds 배열 행을 확장하여 설명을 확인해 보죠
훨씬 낫군요 이제 행을 확장하지 않고도 의미를 명확히 알 수 있지만 Bird 타입의 다른 프로퍼티도 살펴볼게요
이미 일부 새들을 찾아서 사진을 찍었는데요 일부는 photo 프로퍼티인 걸 볼 수 있어요 여기 코뿔바다오리처럼요
행을 클릭하면 새로운 스플릿 뷰 인터페이스에 사진이 나타나는군요 오브젝트의 구조와 프리뷰를 볼 수 있죠
기본적으로는 커스텀 Bird 타입은 행을 클릭했을 때 미리보기가 나오지 않아요 여기서 미리 사진이 나온다면 좋을 것 같군요 모든 종의 이름이 익숙하지 않거든요 이를 위해 사용할 수 있는 건 CustomPlaygroundDisplay Convertible 프로토콜이죠 프로토콜의 이름처럼 이 컨포먼스는 Playground에만 영향을 줘서 Playground의 Sources 디렉터리에 확장 프로그램을 추가할게요
앱 모듈을 임포트 하여 Bird 타입에 접근하고 playgroundDescription과 같은 photo 프로퍼티를 반환하는 간단한 확장 프로그램을 추가할게요
return 문의 Any에 명시적으로 photo를 변환하고 있죠 이게 없으면 값이 옵셔널이라는 중요한 정보를 잃고 있다고 컴파일러에서 경고할 거예요 이 경우에는 Xcode Playgrounds가 옵셔널을 처리하기 위해 오브젝트의 커스텀 설명만 생성하여 playgroundDescription 프로퍼티가 nil 값을 반환하지 않도록 하죠 다시 Playground로 가서 새로운 설명을 확인해 볼게요
Xcode 15에서는 playgroundDescription이 CustomPlaygroundDisplay Convertible 컨폼 타입만 반환하여 오브젝트의 구조와 함께 스플릿 뷰에 표시하죠
이제 사진이 있는 새들은 행을 확장할 필요 없이 빠르게 나타나요 이렇게 하면 커스텀 타입을 이용한 대량 작업이 훨씬 쉬워지죠
하지만 오늘은 사진이 없는 새에 집중할게요 인라인 결과를 닫고 이미 사진이 있는 새들을 걸러내도록 하죠
보다시피 2개의 사이드바 주석이 조금 달라 보입니다 새로운 줄에 다수의 식이 있기 때문이죠 새로운 컨트롤을 클릭하여 각 식의 익숙한 요약을 살펴볼게요
인라인 결과 위를 호버 하면 소스 코드 범위가 강조되죠
이를 통해 배열이 birdsToFind 상수에 할당되어 있다는 것이 확실하며 가장 최신 값은 true로 필터 함수로 보내진 클로저에 의해 도출됐어요
결과 사이드바에 의하면 아직 사진을 찍어야 하는 모든 새의 수가 1,800종 이상이라고 하는데 부담스러운 숫자군요 결국에는 이게 목표겠지만 지금은 숫자를 낮춰서 올빼미처럼 작은 집단에 집중하려고 해요 6월은 올빼미를 찾기에 좋은 시기지만 그건 다른 세션에서 다루도록 하죠 이제 다른 새들을 걸러낼게요
배열에 요소가 5개뿐이어서 도전해 볼만 하군요 커스텀 ChecklistView를 소규모 무리에 적용해 볼게요 그러려면 ChecklistView 인스턴스를 생성하여 새마다 하나씩 추가해야 하죠
ChecklistView의 인라인 결과를 열어 볼게요
UIView의 서브클래스로서 요약과 일부 프로퍼티가 나오죠 Value History 모드로 전환할 건데 이는 새로운 스플릿 뷰 기반의 사용자 인터페이스를 사용해요
ChecklistView가 각 루프 반복문에서 어떤 모습이었는지 볼 수 있죠
제 뷰의 문제를 발견하게 해 줬는데 'birds'가 새 하나를 위한 헤더로 잘못 나와 있어요 새로운 String Catalog의 스트링을 수정하여 문제를 해결할 수 있죠
첫 번째 행은 Checklist View의 헤더에 사용되는 듯해요 컨텍스트 메뉴를 열어서 Vary By Plural을 선택할게요
이렇게 하면 영향받은 행의 상태가 'Needs review'로 바뀌어요 이 스트링의 특이 형태를 조정할게요
새로운 String Catalogs에 관해 더 알고 싶다면 'String Catalogs 발견하기' 세션을 확인해 보세요 이제 playground로 돌아가서 이 사항이 적용된 체크리스트가 어떤 형태인지 보죠
각 루프 반복문의 헤더가 맞게 표시되는군요 이제 인라인 결과를 닫을게요
ChecklistView를 사용할 준비가 된 것 같군요 우리가 사용했던 코드를 불러와서 제 프로젝트의 새 목록을 간추릴게요
ChecklistView 안의 birdsToShow 프로퍼티의 세 줄을 복사할게요
훨씬 작아진 birds 배열에 return 문을 추가할게요
프로젝트를 재실행하기 전에 프로토타이핑할 기능이 1개 있죠 커스텀 Checklist View의 행마다 공개 인디케이터가 있는데 목록의 행을 선택하면 간단한 지도 뷰가 나와요 아직은 유용하지 않지만 선택한 새가 최근에 발견된 곳의 데이터를 불러와서 지도에 표시하려고 하죠 그 기능을 추가하려면 ChecklistView에서 sightingsToShow(for bird:) 함수를 수정해야 해요 이를 위해 프로젝트에 새로운 프로그램을 추가했죠 BirdSightings 패키지는 사람들이 목격 사례를 보고하는 시민 과학 웹사이트의 데이터를 쉽게 가져와요
이 패키지를 사용한 적이 없어서 API에 익숙하지 않죠 다행히 패키지에 포함된 문서에 Playground 형태로 몇 가지 예를 보여 줘요
이런 문서가 있으면 패키지를 사용하는 고객이 제공된 API를 사용해 볼 수 있죠 fetchSightings 함수에 두 개의 인수를 제공해야 할 것 같군요 찾으려는 새의 코드와 살펴볼 지역이에요 이 Playground를 실행하여 기대 결과를 더 알아보죠
이제 Playground로 돌아가서 사용해 볼게요
내비게이터를 닫고 에디터 공간을 확보할게요
함수를 호출하기 전에 2개의 임포트 문을 추가해야 하죠 CoreLocation 프레임워크를 통해 좌표를 작업하고 BirdSighting 프레임워크로 API를 이용할게요
함수의 인자를 위해 목록의 첫 번째 새부터 시작하면 되죠
일단 쇠부엉이를 찾아야 할 것 같군요 여기서 강제 언래핑을 사용했어요 Playgrounds 환경에서는 오류 처리에 관해 많이 걱정할 필요가 없지만 코드를 프로젝트에 가져갈 때 고려해야 해요
장소의 경우 대개는 현재 장소를 사용하겠지만 특정 좌표를 제공하는 기능이 2가지 면에서 좋죠 코드를 검증하고 여행을 계획하는 거예요 Apple Park에서는 뭘 찾을 수 있는지 보죠
네트워크 호출을 시작하기 전에 playground 실행을 수동으로 전환하여 불필요한 호출을 제거해요 이런 요청은 시간이 걸리는데 새로운 기능을 최대한 빨리 반복해 보고 싶거든요 그러려면 하단 바에서 메뉴를 선택하여 'Manually Run'을 선택할게요
이제 실행돼야 하는 부분의 코드를 완벽하게 제어할 수 있죠 자료를 가져오는 코드를 추가할게요
소스 에디터 거터의 컨트롤을 보면 두 줄을 실행해도 위에서 이미 실행된 줄은 재실행되지 않죠 이제 새로운 줄을 실행하여 데이터가 나오는지 볼게요
다행히 목격 사례가 있네요 제일 최근 사례인 첫 번째를 살펴보죠
쇠부엉이를 가장 최근에 발견한 건 창멘 절벽 보호 지구군요 저는 유명한 새 관찰 지역에 익숙하지 않아서 SightingMapView에서 목격 자료를 보면 좋겠군요 가져온 목격 사례 데이터로 초기화할게요
지도 뷰와 같은 복잡한 사용자 인터페이스 요소에는 Playgrounds 라이브 뷰를 사용하여 상호작용이 가능한 대형 프리뷰를 볼 수 있어요 사용하려면 PlaygroundSupport 프레임워크를 임포트 해야 하죠
이제 라이브 뷰를 설정하여 Playground를 실행할 수 있어요
파일 최상단에 임포트 문을 추가하여 Playground에서 실행된 부분을 수정했더니 소스 에디터 거터의 컨트롤에서 전체 파일을 재실행해야 한다고 나오죠 이전 실행의 결괏값을 모두 잃겠지만 이 경우에는 문제가 되지 않으므로 Playground를 실행할게요
Apple Park 근처에는 섬이 없었던 것 같은데요 라이브 뷰는 상호작용이 가능해서 조금 축소할 수 있는데 iPhone 시뮬레이터에서 현재 위치를 확인하는 것과 같죠
너무 동쪽으로 갔군요 Editor Options에서 라이브 뷰를 닫고 어디서 문제가 시작됐는지 알아볼게요
mostRecentSighting 상수로 SightingMapView가 초기화됐죠 값을 확인해 볼게요 인라인 결과를 여는 대신 값을 빠르게 살펴보기 위해 사이드바의 눈 아이콘을 클릭할게요
Xcode 15에서 일부 MapKit와 CoreLocation 타입의 playground 결괏값을 개선했어요 CLLocationCoordinate2D 프리뷰를 Playgrounds에서 볼 수 있으니 location 프로퍼티를 살펴보죠
같은 위치가 나오는 걸로 봐서 SightingMapView가 원인이 아닌 듯하군요 BirdSightings 패키지에서 잘못된 위치를 가져왔는데 패키지에 문제가 있거나 애초에 잘못된 위치를 통과시켰을 수도 있죠 후자를 확인해 볼게요
이것도 Apple Park 근처가 아닌 듯하군요 너무 동쪽으로 가서 서쪽과 동쪽을 바꿔야 하는 문제일 수도 있어요 경도 앞에 마이너스 기호를 추가한 뒤 Playground를 재실행 보도록 하죠
이건 확실히 Apple Park예요 이제 업데이트된 위치 정보로 Playground의 나머지를 실행하고 Editor Options의 라이브 뷰를 다시 열도록 하죠
훨씬 낫네요 Coyote Hills가 새를 촬영하기에 최고의 장소라는 걸 알죠 ChecklistView에 데이터를 가져오는 코드를 불러올게요
여기 세 줄을 복사하여 sightingsToShow 함수에 넣을게요
매번 하드 코딩된 Apple Park 위치를 사용하는 대신 CLLocationManager에서 가져온 lastCurrentLocation으로 대체하도록 하죠
새로운 mostRecentSighting에 return 문도 추가할게요
이제 모든 수정 사항을 적용한 프로젝트를 실행해 보죠
더 작은 집단의 새로 범위를 좁혔더니 현실적인 체크리스트가 됐어요 이제 행을 클릭하면 어떻게 되는지 보죠
좋아요 선택한 새의 최신 목록 사례가 앱에 나타나죠 물론 아직도 개선의 여지가 많아요 예를 들어 백그라운드에서 목격 사례를 가져올 때 진행 상황을 보여 줄 수도 있죠 그래도 출발이 좋군요 이 앱은 벌써 많은 도움이 되며 Xcode Playgrounds를 통해 이런 개선 사항을 훨씬 쉽게 작업할 수 있었죠 이번 세션에서는 Xcode Playgrounds를 이용하여 프로젝트의 새로운 기능을 빠르게 프로토타이핑했어요 CustomStringConvertible과 CustomPlaygroundDisplay Convertible 프로토콜로 커스텀 타입이 나타내는 걸 커스터마이징했죠 Playground 실행 모드를 수정하여 작업 흐름을 향상시켰고 Value History 모드를 통해 다양한 입력에 클래스가 어떻게 반응하는지 봤어요 마지막으로 Playground의 라이브 뷰를 사용하여 복잡한 사용자 인터페이스 요소를 자세히 살펴봤죠 시청해 주셔서 감사해요
-
-
2:04 - birdsToShow computed property before the required changes
var birdsToShow: [Bird] { // TODO: Narrow down the list of birds to find. let birdProvider = BirdProvider(region: .northAmerica) return birdProvider.birds }
-
4:15 - birdProvider instance
let birdProvider = BirdProvider(region: .northAmerica)
-
6:31 - CustomStringConvertible
extension Bird: CustomStringConvertible { public var description: String { return "\(commonName) (\(scientificName))" } }
-
8:17 - CustomPlaygroundDisplayConvertible
extension Bird: CustomPlaygroundDisplayConvertible { public var playgroundDescription: Any { return photo as Any } }
-
9:45 - Birds without a photo
let birdsToFind = birdProvider.birds.filter { $0.photo == nil }
-
10:52 - Owls without a photo
let owlsToFind = birdsToFind.filter { $0.family == .owls }
-
11:15 - Verifying the ChecklistView
let checklist = ChecklistView() for bird in owlsToFind { checklist.add(bird) }
-
13:41 - birdsToShow computed property with the required changes
var birdsToShow: [Bird] { let birdProvider = BirdProvider(region: .northAmerica) let birdsToFind = birdProvider.birds.filter { $0.photo == nil } let owlsToFind = birdsToFind.filter { $0.family == .owls } return owlsToFind }
-
14:21 - sightingToShow function before the required changes
func sightingToShow(for bird: Bird) -> Sighting? { // TODO: Use BirdSightings package to fetch the most recent sighting. return nil }
-
15:04 - BirdSightings package example
let barnOwlCode = "BNOW" let centralParkLocation = CLLocationCoordinate2D(latitude: 40.785091, longitude: -73.968285) let sightingsProvider = SightingsProvider() sightingsProvider.fetchSightings(of: barnOwlCode, around: centralParkLocation)
-
16:08 - Parameters for sightings fetching
let bird = owlsToFind.first! let appleParkLocation = CLLocationCoordinate2D(latitude: 37.3348655, longitude: 122.0089409)
-
17:31 - Sightings fetching
let sightingsProvider = SightingsProvider() let sightings = sightingsProvider.fetchSightings(of: bird.speciesCode, around: appleParkLocation)
-
18:23 - Initializing the SightingMapView
let mostRecentSighting = sightings.first let sightingMapView = SightingMapView(sighting: mostRecentSighting)
-
18:55 - Setting up the playground's live view
import PlaygroundSupport PlaygroundPage.current.liveView = sightingMapView
-
22:20 - sightingToShow function with the required changes
func sightingToShow(for bird: Bird) -> Sighting? { let sightingsProvider = SightingsProvider() let sightings = sightingsProvider.fetchSightings(of: bird.speciesCode, around: lastCurrentLocation) let mostRecentSighting = sightings.first return mostRecentSighting }
-
-
찾고 계신 콘텐츠가 있나요? 위에 주제를 입력하고 원하는 내용을 바로 검색해 보세요.
쿼리를 제출하는 중에 오류가 발생했습니다. 인터넷 연결을 확인하고 다시 시도해 주세요.