묻고 답해요
148만명의 커뮤니티!! 함께 토론해봐요.
인프런 TOP Writers
-
미해결성공적인 진짜 iOS 개발자 되기 [기초부터 실무까지]
table view 없음
show library 에 table view가 없는
-
해결됨Combine - iOS의 Reactive Programming
merge 오퍼레이터 질문
안녕하세요.stream은 시간이 지남에 따라 변하는 어떤 상태로 이해했는데요.publisher1과 publisher2에서의 stream을 각 stream1, stream2라고 했을때 시간이 지남에 따라 동시에 상태가 변하면 해당 상태는 merge 오퍼레이터에서 방출은 어떻게 처리하나요? [동시가 아닌 경우]-1-2-3---4--5--6---> 1-4-2-5-3-6 [동시인 경우]-1-2-3--4-5-6--> ?????
-
해결됨Combine - iOS의 Reactive Programming
zip 오퍼레이터 설명하는 부분에서 강의가 짤렸습니다.
안녕하세요. zip 오퍼레이터 설명하는 부분에서 강의가 짤려 있습니다.
-
미해결앨런 iOS 앱 개발 (15개의 앱을 만들면서 근본원리부터 배우는 UIKit) - MVVM까지
섹션8] 코드 리팩토링 문의
섹션8 선생님의 코드 노션에서 개발시 참고할 수 있게 작성한코드 깃이 아닌 노션에 올려서 정리 자료로 써도 될까요. 노션 정리내용은 공개하여 취업할때 url공개하여 포트폴리오 자료에 붙여서 공개 될 수 있어서 문의드립니다.우선 많은 수정 가한 코드입니다.프로퍼티는 클로저, 메서드, 메서드에 설정 세가지 형식을 적용하고 objc 로 구현된 부분 순수 swift로 돌리는 부분 추가 코드 리팩토링 하였습니다.아래는 전체 수정한 코드입니다.노션에 올려도 될까요?여러 방식 찾아가며 다시 치는데 4시간 걸렸어요 ㅠㅠ아래와 같이 수정하였어요.
-
해결됨Part1: 진짜 왕초보 iOS 배우기(SwiftUI, SwiftData, 2024)
List를 넣으니 위치가 제대로 조정이 되던데 그럼 Spacer는 따로 넣을 필요가 없는걸까요?
안녕하세요 선생님. wordRelay 강의 잘 수강하였습니다. 강의를 다 수강한 뒤에 복습하고자 수업 진행했던 코드를 처음부터 다시 따라 치던 와중에 끝말잇기 게임 타이틀과 단어 입력창, 확인 버튼 밑에 Spacer를 따로 넣지 않고 List만 넣어도 위치가 원하는대로 위로 올라가는데, 그럼 Spacer는 따로 넣어주지 않아도 되는건가요? Spacer를 넣는 것과는 어떤 차이가 있나요?import SwiftUI struct ContentView: View { let title: String = "끝말잇기 게임" @State var nextWord = "" @State var words: [String] = ["Apple", "Elsa", "Alin"] @State var showAlert: Bool = false var body: some View { VStack { Text(title) .padding(.horizontal, 12) .padding(.vertical, 16) .font(.title) .bold() .background( RoundedRectangle(cornerRadius: 15) .fill(.purple) .opacity(0.3) .shadow(radius: 5) ) .padding(.top, 10) } HStack { TextField("단어를 입력하세요", text: $nextWord) .padding() .background( RoundedRectangle(cornerRadius: 10) .stroke(lineWidth: 2) ) Button(action: { if words.last?.last?.lowercased() == nextWord.first?.lowercased() { words.append(nextWord) nextWord = "" } else { showAlert = true nextWord = "" } }, label: { Text("확인") .foregroundStyle(Color.white) .padding() .background( RoundedRectangle(cornerRadius: 10) ) }) .alert("끝말이 이어지는 단어를 입력하세요", isPresented: $showAlert) { Button("확인", role: .cancel) { showAlert = false } } } .padding(.horizontal) .padding(.top) List { ForEach(words.reversed(), id: \.self) { word in Text(word) .font(.title) } } .listStyle(.plain) // 선생님은 여기에 Spacer()를 넣으셨는데 // 입력하지 않아도 타이틀과 단어 입력창의 위치가 // 위로 올라갑니다 } } #Preview { ContentView() }
-
미해결[Lv.2] SwiftUI 중급 - Core Data와 SwiftData로 앱 완성하기
CoreData Array의 변화에 따른 SwiftUI View 변화 적용(with @Observable Macro)
지난번과 동일하게 자꾸, @Observation을 활용하려다보니 문제가 많이 생기는 것 같습니다.정확하게 차이를 이해하려고 강의를 돌려봐도 제가 이해하고 있는 바와 다른 점들이 있는 것 같아 질문 드립니다. 강의의 내용은 CoreData를 다룰 때, fetch로 불러온 것을 View로 넘기기위한 변수 var savedEntities: [Fish] 를 만들고, :ObservableObject protocol을 활용하셨습니다. 이후 View에서 ViewModel을 처음 초기화할 때 사용하기 위해서 @Stateobject를 활용하여 설명을 하셨고요. 그렇다면, Observable Macro로 Migrating하기 진행하는데에도 문제가 없다고 생각을 했습니다.그래서, 아래와 같이 코드를 바꾸어 보았습니다. 그런데 문제는 Viewmodel에서 정의된 updateFish() method 가 적용되지 않습니다.List에서 주어진 생선 이름을 tap했을 경우, "~" 가 추가가 되어야 하는데,func updateFish(fish: Fish){ let currentName = fish.name ?? "" let newName = currentName + "~" fish.name = newName saveData() print("Updating fish name to: \(newName)") }와 같이 print를 찍어보았을 때, 디버그 창에서는 print가 되지만,View에서는 "~"가 추가되지 않는 모습을 확인할 수 있었습니다.CoreData의 변화를 감지하지 못하는건지.. 기초강의에서 FruitModel 예시에서는 ObservableObject대신 Observable Macro를 적용해도 되었었거든요.여기서도 fruitArray이라는 배열을 사용했는데 잘 적용되었습니다.@Observable Macro를 적용하는데에 있어서 제가 잘못 이해하고 있는 부분이 있을까요?var fruitArray: [FruitModel] 는 View에서 변화를 감지하여 실시간 Update가 가능한 반면var savedEntities: [Fish] 는 왜 변경되어도 View에서 변화를 감지 하지 못하는지 궁금합니다. 감사합니다.
-
미해결앨런 iOS 앱 개발 (15개의 앱을 만들면서 근본원리부터 배우는 UIKit) - MVVM까지
xcode 에서 ios 버전 선택 및 시뮬레이터 관련 질문
안녕하세요... 최근에 강의를 수강하기 시작한 수강생입니다. 현재 기초앱1, 2를 따라하고 있는 중입니다. 현재 제가 사용하고 있는 Xcode 버전이 16.2 입니다.ios App을 설정할 때, 최소 ios가 15.6이 최소 버전으로 나오고, 시뮬레이터에서 선택할 때 있는 아이폰 기종도 iPhone 16 이상으로 나옵니다. 강사님이 강의에서 언급하시는 설정에서 출시버전을 ios 13.0을 최소버전으로 선택하시는 것 같은데, 어떻게 해야 현재 제가 가진 xcode 버전에서 ios의 출시버전을 13.0으로 설정할 수 있을까요? 또 시뮬레이터 사용시 iphone 12를 선택할 수 있을까요?
-
미해결앨런 Swift Concurrency for Swift 6 (Part-1)
파트1 PDF 강의 자료 다운로드
파트1 PDF 강의 자료 다운로드 받고 싶은데, 어디서 받을 수 있는지 모르겠습니다.
-
해결됨앱 개발 기초부터 실전까지 하나로 끝내는 Swift & iOS 마스터 클래스
오류를 원인을 알고 싶습니다.
강의를 듣던중 잘 따라가나 했는데, 틀리게 결과가 나오는 부분이 있어 질문 드립니다.강좌는 앱개발 기초부터 실전까지 하나로 끝내는 Swift & iOS 마스터 클래스 이고, 섹션9의 Step #5 - 도시목록 입니다.잘 따라가나 했는데, 위의 결과처럼 나옵니다.뭐가 문제인지를 알고 싶습니다.바쁘시겠지만 한번만 봐주시고, 조언 부탁드립니다.
-
미해결앨런 iOS 앱 개발 (15개의 앱을 만들면서 근본원리부터 배우는 UIKit) - MVVM까지
수강 기간 연장 부탁드려도 될까요?
앨런님 안녕하세요!앱 만들기 강의를 깜빡하고 있다가 급히 듣고 있는데완강하기에 기간이 조금 촉박할 것 같아서요..수강기간 연장 부탁드려도 될까요 ㅠㅠ?
-
미해결앨런 iOS 앱 개발 (15개의 앱을 만들면서 근본원리부터 배우는 UIKit) - MVVM까지
뷰모델의 상태변화 와 didSet
class MusicViewModel { var music: Music? { didSet { onCompleted() // 시점을 알려줌 } } var onCompleted: () -> () = { } } class ViewController: UIViewController { var viewModel = MusicViewModel() override func viewDidLoad() { super.viewDidLoad() viewModel.onCompleted = { self.configureUI() } // 뷰모델에서 클로저를 호출하면 이부분이 호출됨 }안녕하세요 앨런님!궁금한게 있어서 질문 남기게 되었습니다.섹션 뒤쪽에 MVVM 강의에서 뷰모델의 상태변화를 코드를 보면,뷰모델에서 데이터에 상태변화가 생기면 didSet을 통해 onComplete() 시점을 알려주고, 뷰컨트롤러에서는 해당 onComplete에 ui업데이트를 하는 함수를 실행코드를 넣어주게됩니다! 이렇게 didSet과 클로저를 통해서 뷰모델과 뷰컨에서의 ui 업데이트를 하는 코드가 현업에서도 많이 사용하는지 궁금합니다! 이 방법외에도 Combine을 사용해도 되는건지도 궁금합니다! 항상 친절하게 답변 남겨주셔서 너무 감사합니다 :)새해복 많이 받으세요 🧧
-
미해결앨런 iOS Concurrency(동시성) - 디스패치큐와 오퍼레이션큐의 이해
오퍼레이션 큐 질문
오퍼레이션 큐는 기본적으로 1번 쓰레드에서 동기적으로 처리 된다고 하셨는데 이전 강의들을 보면 1번 쓰레드는 메인 쓰레드라고 언급하셨던 걸로 기억하는데요. 맞을까요?맞다면 메인쓰레드는 동기적으로 처리하면 안되는데 Operation을 오퍼레이션큐에 넣지 않고 사용한다면 잘못된 상용법인 인가요?
-
미해결앨런 Swift문법 마스터 스쿨 (온라인 BootCamp - 2개월과정)
서약서 다운로드 압출 풀기 불가
안녕하세요, 선생님.좀 전에 막 강의 결제를 하고, 서약서를 다운로드 받았는데요.파일이 압축이 된 상태라 '압축 풀기' 버튼을 눌렀더니 '경로에 압축을 풀지 못하게 하는 문자가 들어있다'면서 압축이 안풀립니다.
-
미해결[Lv.1] iOS 17 앱 개발 기초 - SwiftUI로 시작하기
Xcode version 문제
강의 관련된 질문은 언제나 환영입니다 😄코드 관련 상세하게 작성해주시면 더 좋아요! (상세코드를 붙여넣기 해주세요)마크다운을 사용해서 편리하게 글을 작성하세요먼저 유사한 질문이 있었는지 먼저 검색 해보는 습관~인프런 서비스 운영 관련 문의는 1:1 문의하기를 이용해주세요안녕하세요. 제이콥강사님이제 막 시작하는 새내기입니다. 제가 설치한 Xcode 버전이 16버전인데, 혹시 이 버전으로 해도 문제가 없을까요??답변 부탁드립니다.
-
미해결[Lv.2] SwiftUI 중급 - Core Data와 SwiftData로 앱 완성하기
init-deinit의 무한루핑을 벗어나는 방법이 궁금합니다.
ObservableObject를 활용하는 것보다,새로운 Observable Macro를 활용하여 Migrating을 시도하려 했습니다.주어진 WeakSelfInterViewModel 에 대해 @Observable을 적용하고, var data String? = nil 로 property를 만들었습니다. 하지만 Init과 Deinit이 반복되어 나타나는 무한루핑이 발생하였습니다. class WeakSelfInterViewModel{ var data: String? = nil ... } struct WeakSelfInter2: View { @State var vm: WeakSelfInterViewModel = WeakSelfInterViewModel() ... } 어떻게 해결할 수 있을까요?
-
미해결앨런 iOS 앱 개발 (15개의 앱을 만들면서 근본원리부터 배우는 UIKit) - MVVM까지
@Sendable 키워드
- 학습 관련 질문을 남겨주세요. 상세히 작성하면 더 좋아요! - 먼저 유사한 질문이 있었는지 검색해보세요. - 서로 예의를 지키며 존중하는 문화를 만들어가요. - 잠깐! 인프런 서비스 운영 관련 문의는 1:1 문의하기를 이용해주세요.안녕하세요 앨런님 저는 현재 활용 76강을 듣고 있는데요! func getMethod(completion: @escaping ([Music]?) -> Void) { // URL구조체 만들기 guard let url = URL(string: "https://itunes.apple.com/search?media=music&term=bts") else { completion(nil) return } // URL요청 생성 var request = URLRequest(url: url) request.httpMethod = "GET" // 요청을 가지고 작업세션시작 URLSession.shared.dataTask(with: request) { data, response, error in // 에러가 없어야 넘어감 guard error == nil else { print("Error: error calling GET") print(error!) completion(nil) return } // 옵셔널 바인딩 guard let safeData = data else { print("Error: Did not receive data") completion(nil) return } // HTTP 200번대 정상코드인 경우만 다음 코드로 넘어감 guard let response = response as? HTTPURLResponse, (200 ..< 299) ~= response.statusCode else { print("Error: HTTP request failed") completion(nil) return } // 원하는 모델이 있다면, JSONDecoder로 decode코드로 구현 ⭐️ do { let decoder = JSONDecoder() let musicData = try decoder.decode(MusicData.self, from: safeData) completion(musicData.results) } catch { } }.resume() // 시작} 해당 코드에서 위와같은 에러가 발생하여 @Sendable을 붙이니 해결이 되었습니다. 강의에서는 에러가 안나는 이유는 버전 차이 때문에 그런거라고 이해하면 될까요?
-
미해결앨런 iOS 앱 개발 (15개의 앱을 만들면서 근본원리부터 배우는 UIKit) - MVVM까지
클로저
- 학습 관련 질문을 남겨주세요. 상세히 작성하면 더 좋아요! - 먼저 유사한 질문이 있었는지 검색해보세요. - 서로 예의를 지키며 존중하는 문화를 만들어가요. - 잠깐! 인프런 서비스 운영 관련 문의는 1:1 문의하기를 이용해주세요.안녕하세요 앨런님 제가 강의를 순서대로 듣는게 아니고 중간 중간 듣고 있어서 질문 드립니다! 혹시 강의에 클로저와 escaping 부분을 추가적으로 설명해주시는 부분들도 따로 있나요?강의 중간중간 이전에 이 부분은 설명했다고 나오는데, 확실히 어딘지 알 수가 없어서 질문 드립니다!
-
미해결
스위프트, UIKit 에서 테이블 뷰 내 텍스트뷰 높이 조절
지금 당근마켓의 내물건 팔기를 구현하고 있습니다. 전체적으로 UITableView로 만들고 각 셀마다 맞는 셀을 구현했습니다. 텍스트 뷰에 글을 작성하면 텍스트뷰의 높이가 글자 수에 맞춰 늘어나는데, 이때 키보드는 화면 하단에 고정되어 있는것으로 판단됩니다. 그래서 아래와 같이 구현해봤습니다. class FeedViewController: UIViewController { // MARK: - Variable private let tableSection: [String] = ["이미지", "제목", "내용"] var selectedImages: [UIImage] = [] // MARK: - UI Components private let feedTableView: UITableView = { let tableView = UITableView(frame: .zero, style: .insetGrouped) tableView.separatorStyle = .none tableView.showsVerticalScrollIndicator = false tableView.alwaysBounceVertical = false tableView.isScrollEnabled = true return tableView }() ... // MARK: - Layout private var feedTableViewBottomConstraint: NSLayoutConstraint! private var registerButtonTopConstraint: NSLayoutConstraint! private func configureConstraints() { view.addSubview(feedTableView) view.addSubview(registerFeedButton) feedTableView.translatesAutoresizingMaskIntoConstraints = false registerFeedButton.translatesAutoresizingMaskIntoConstraints = false // 제약 조건 저장 feedTableViewBottomConstraint = feedTableView.bottomAnchor.constraint(equalTo: registerFeedButton.topAnchor, constant: -10) registerButtonTopConstraint = registerFeedButton.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor, constant: -10) NSLayoutConstraint.activate([ // 테이블뷰 제약조건 feedTableView.leadingAnchor.constraint(equalTo: view.leadingAnchor), feedTableView.trailingAnchor.constraint(equalTo: view.trailingAnchor), feedTableView.topAnchor.constraint(equalTo: view.topAnchor), feedTableViewBottomConstraint, // 버튼 제약조건 registerFeedButton.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 15), registerFeedButton.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -15), registerFeedButton.heightAnchor.constraint(equalToConstant: 50), registerButtonTopConstraint ]) // 키보드 노티피케이션 설정 setupKeyboardNotifications() } private func setupKeyboardNotifications() { NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillShow(_:)), name: UIResponder.keyboardWillShowNotification, object: nil) NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillHide(_:)), name: UIResponder.keyboardWillHideNotification, object: nil) } @objc private func keyboardWillShow(_ notification: Notification) { if let keyboardFrame = notification.userInfo?[UIResponder.keyboardFrameEndUserInfoKey] as? CGRect { // 키보드가 올라오면 테이블뷰의 bottom을 키보드의 top에 맞춤 feedTableViewBottomConstraint.constant = -keyboardFrame.height + 100 UIView.animate(withDuration: 0.3) { self.view.layoutIfNeeded() } } } @objc private func keyboardWillHide(_ notification: Notification) { // 키보드가 내려가면 테이블뷰의 bottom을 버튼의 top으로 복원 feedTableViewBottomConstraint.constant = -10 UIView.animate(withDuration: 0.3) { self.view.layoutIfNeeded() } } 그리고 ContentInputCell 이라고해서 텍스트뷰를 입력하는 곳에는 아래와 같이 작성했습니다. // MARK: - UI Component private let contentTextView: UITextView = { let textView = UITextView() textView.text = "오늘 하루는 어땠나요? 😀" textView.backgroundColor = .systemBackground textView.layer.cornerRadius = 5 textView.layer.masksToBounds = true // 글자 수에 따라 크기가 늘어가게 하기 위함 textView.isScrollEnabled = false textView.textAlignment = .left textView.textContainerInset = UIEdgeInsets(top: 10, left: 10, bottom: 10, right: 10) textView.textColor = .secondaryLabel textView.backgroundColor = .systemBackground textView.font = UIFont.systemFont(ofSize: 16, weight: .bold) return textView }() ... private func configureConstraints() { contentView.addSubview(contentTextView) contentTextView.translatesAutoresizingMaskIntoConstraints = false NSLayoutConstraint.activate([ contentTextView.leadingAnchor.constraint(equalTo: contentView.leadingAnchor), contentTextView.trailingAnchor.constraint(equalTo: contentView.trailingAnchor), contentTextView.topAnchor.constraint(equalTo: contentView.topAnchor), contentTextView.bottomAnchor.constraint(equalTo: contentView.keyboardLayoutGuide.topAnchor, constant: 5), contentTextView.heightAnchor.constraint(greaterThanOrEqualToConstant: 350) ]) } // MARK: - Extension: UITextViewDelegate extension ContentInputCell: UITextViewDelegate { func textViewDidChange(_ textView: UITextView) { guard let tableView = tableView else { return } let contentSize = textView.sizeThatFits(CGSize(width: textView.bounds.width, height: .infinity)) if textView.bounds.height != contentSize.height { tableView.contentOffset.y += contentSize.height - textView.bounds.height UIView.setAnimationsEnabled(false) tableView.beginUpdates() tableView.endUpdates() UIView.setAnimationsEnabled(true) } } } extension ContentInputCell { var tableView: UITableView? { var view = superview while view != nil && !(view is UITableView) { view = view?.superview } return view as? UITableView } }
-
미해결앨런 iOS 앱 개발 (15개의 앱을 만들면서 근본원리부터 배우는 UIKit) - MVVM까지
ThreadSafe하지 않을때 해경 방법
- 학습 관련 질문을 남겨주세요. 상세히 작성하면 더 좋아요! - 먼저 유사한 질문이 있었는지 검색해보세요. - 서로 예의를 지키며 존중하는 문화를 만들어가요. - 잠깐! 인프런 서비스 운영 관련 문의는 1:1 문의하기를 이용해주세요안녕하세요 앨런님 수업을 듣다가 궁금한 점이 생겨서 질문 드립니다! Thread Safe하지 않을 때의 해결 방법이 다시 시리얼큐로 보내는 방법이라고 하셨는데 이때 Task 전체를 다 큐로 보내는 건가요?? 아니면 힙 메모리에 동시에 접근하는 그 일부의 작업만 보내는 건가요?
-
미해결앨런 iOS 앱 개발 (15개의 앱을 만들면서 근본원리부터 배우는 UIKit) - MVVM까지
com()이 붙는이유
- 학습 관련 질문을 남겨주세요. 상세히 작성하면 더 좋아요! - 먼저 유사한 질문이 있었는지 검색해보세요. - 서로 예의를 지키며 존중하는 문화를 만들어가요. - 잠깐! 인프런 서비스 운영 관련 문의는 1:1 문의하기를 이용해주세요.안녕하세요 앨런님 ! 혹시 강의 준 문법 179강에서 아래와 같은 예시를 들어주셨는데요! func doSomething(com: @escaping(Void) -> Void) {DispathchQueue.global().async {print("프린트시작")sleep(3)print("프린트 종료")com()}}print("1")doSomething()print("2")해당 함수에서 꼭 com()컴플리션 핸들러가 들어가야 하나요? 아니면 해당 예시에서는 없어도 되는 걸까요?