API에서 contents에서 아예 HTML이 온다면 어떻게 해야 깔끔하게 뷰로 보여줄 수 있을까? Webview로 보여주면 간단하겠지만... 그건 원하지 않았다. 그 밑에 들어올 뷰들이 있고, 내가 하고싶은거는 HTML을 네이티브 텍스트처럼 렌더링 하는 일이었기 때문이다. 찾아보니 UIKit에 있는 UITextView에 attributedText에 넣으면 가능하다는걸 알았다. UIViewRepresentable을 채택해서 PostHTMLView을 만들었다. struct HTMLView: UIViewRepresentable { let html: String func updateUIView(_ uiView: UITextView, context: UIViewRepresentableContext) { Disp..
stackoverflow.com/questions/65209314/what-does-the-underscore-mean-before-a-variable-in-swiftui-in-an-init What does the underscore mean before a variable in Swiftui in an init()? What does the underscore mean before momentDate? Why is it needed? stackoverflow.com 변수이름 앞에 언더바를 붙이는 코딩스타일은 스위프트에서는 지양해오던 바 였다. (Property Wrapper내부에서 사용하던 코딩 스타일이었다.!! 일반 변수에서 사용하는걸 지양했다는 뜻이다.) 그러나, Combine에서 Binding변..
이런식으로 기간 양쪽으로 움직일 수 있는 슬라이더가 필요했다. 기존의 SwiftUI Slider는 한쪽밖에 핸들이 달려있지 않아서, 반대쪽도 있는 슬라이더를 찾아왔다. import SwiftUI import Combine //SliderValue to restrict double range: 0.0 to 1.0 @propertyWrapper struct SliderValue { var value: Double init(wrappedValue: Double) { self.value = wrappedValue } var wrappedValue: Double { get { value } set { value = min(max(0.0, newValue), 1.0) } } } class SliderHandle: ..
이런 캘린더가 필요했는데... 많은 고민 끝에 FSCalendar을 SwiftUI로 바꿔서 쓰기로 결정했다. struct CalendarView: UIViewRepresentable { typealias UIViewType = FSCalendar func makeUIView(context: Context) -> FSCalendar { let calendar = FSCalendar() calendar.delegate = context.coordinator calendar.dataSource = context.coordinator return calendar } func updateUIView(_ uiView: FSCalendar, context: Context) {} class Coordinator: NS..
비밀번호를 평문으로 보내면 네트워크를 타고 가는 중에서 비번이 털릴 수도 있다. 그래서 만든것이 RSA encryption! 이렇게 서버개발자가 만들어준 public-key API를 호출해서 publicKey를 받고, encrypted 해준다! 그렇게 해서 나온 encrypted랑, publicKey를 같이 Login시 보내주면 된다. 사용한 라이브러리는 : github.com/TakeScoop/SwiftyRSA extension String { func rsaEncryption(publicKey: String) -> String { let publicKey = try! PublicKey(base64Encoded: publicKey) let clear = try! ClearMessage(string: s..
선택 했을때, 안했을 때! cornerRadius랑 background때문에 약간 고생했다 ㅠ struct GenderStyle: ButtonStyle { @State var isSeleceted: Bool func makeBody(configuration: Configuration) -> some View { configuration.label .padding(.vertical, 12) .padding(.horizontal, 45) .foregroundColor(isSeleceted ? Color.white : Color("coolGrey")) .background(isSeleceted ? Color("lightPeriwinkle") : Color.white) .cornerRadius(8) .overl..
// 웹뷰 약관 보여주기용 struct PolicyView: UIViewRepresentable { var policyType: Policy func makeUIView(context: Context) -> WKWebView { let webView = WKWebView() let request = URLRequest(url: policyType.url) webView.load(request) return webView } func updateUIView(_ uiView: WKWebView, context: Context) {} class Coordinator {} func makeCoordinator() -> Coordinator { return Coordinator() } } enum Policy {..
일단 볼게, 1. navigation 만들기 2. custom backbutton 만들기 3. pop to root view 만들기 4. 코드로 navigation 실행하기 이렇게 4개 할 예정이다! 일단 나는 title이랑 navigationButton을 같이 쓰는 화면이 엄청 많아서, 미리 ViewModifier을 만들어 뒀다. struct BackButtonAndTitle: ViewModifier { var title: String var backButtonAction: () -> () func body(content: Content) -> some View { HStack { Button(action: { self.backButtonAction() }, label: { }).buttonStyle(..
계속 네아로 네아로 하길래 뭔가 했는데 '네이버 아이디로 로그인'이다. 심지어 공식명칭임;;;; [깃허브 링크] github.com/naver/naveridlogin-sdk-ios [사전 준비 사항] developers.naver.com/docs/common/openapiguide/appregister.md [가이드 링크] developers.naver.com/docs/login/ios/ +) 외주사에서 앱 등록 하고 'cliendId'랑 'clientSecret'을 알려달라고 해야한다. 자기가 직접 등록해야한다면 여기 에서 하자! 등록하다보면 '앱 다운로드 URL'을 입력해야 하는데, 아직 배포 전이라면 회사 홈페이지 등을 링크해도 괜찮다. 그리고 알아야 할 부분이, 안드로이드는 로그인 콜백 처리(사용..
print(UIDevice.currentDevice().name) print(UIDevice.currentDevice().model) print(UIDevice.currentDevice().localizedModel) print(UIDevice.currentDevice().systemName) print(UIDevice.currentDevice().systemVersion) print(UIDevice.currentDevice().orientation) //결과 값 iPhone Simulator iPhone iPhone iPhone OS 9.3
UIKit에서는 UIButton을 상속받은 클래스를 만들었듯... SwiftUI에서는 ButtonStyle을 사용하게 된다! struct HomeScrollButtonStyle: ButtonStyle { var isSelected = false func makeBody(configuration: Self.Configuration) -> some View { VStack { configuration.label .foregroundColor(isSelected ? Color.red : Color.black) .font(isSelected ? .largeTitle : .body) if isSelected { Circle().frame(width: 5, height: 5, alignment: .center) }..
1. 이미지를 baseString으로 바꿔서, String으로 전송하기 2. 이미지를 Data로 전환해서 Multipart로 전송하기 주로 서버 개발자들이 2번으로 많이 해서 주는듯 하다. postman도 다음과 같이 Body가 form-data로 되어있는걸 확인할 수 있다. 사실 나는 단순히 header에 content type을 multipart로 설정하고, JSON에 담아서 보내면 될 줄 알았는데 그건 아닌 것 같다. 기존에 JSON같은 경우에는 JSONSerialization.data(withJSONObject:)를 사용했는데 form-data는 그것보다는 조금 복잡하다. func uploadImage(paramName: String, fileName: String, image: UIImage) ..
preview실행하면 실제로 실행도 해볼 수 있다!!! [Code] import SwiftUI struct BottomMenuView: View { var body: some View { TabView { AnnoucementView() .tabItem { Image("announcementNormal") Text("공지") } SafetyMapView() .tabItem { Image("mapNormal") Text("안전지도") } CouponView() .tabItem { Image("couponNormal") Text("쿠폰함") } } } } struct BottomMenuView_Previews: PreviewProvider { static var previews: some View { Bot..
@Binding: SwiftUI ----(data)---> UIKit Coordinator: UIKit ----(data)---> SwiftUI Coordinator을 쓰면, UIKit의 delegate를 구현할 수 있다. class Coordinator: NSObject, UISearchBarDelegate { @Binding var text: String init(text: Binding) { _text = text } func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) { text = searchText } } struct SearchBarView: UIViewRepresentable { @Binding var tex..
일단, UIKit에 있는것들을 사용하려면 'UIViewRepresentable' 을 채택해야하는건 원래 알고 있었다. import Combine import NMapsMap import SwiftUI struct ContentView: View { var body: some View { NaverMapView() .edgesIgnoringSafeArea(.all) } } struct ContentView_Previews: PreviewProvider { static var previews: some View { ContentView() } } struct NaverMapView: UIViewRepresentable { func makeUIView(context: Context) -> NMFMapView ..
@testable import
stackoverflow.com/questions/44682626/swifts-jsondecoder-with-multiple-date-formats-in-a-json-string JSONDecoder.decode()를 할때, 이런식으로 decoder의 dateFormat을 정할 수 있다. 근데, decode하려는 객체에 들은 Date 포맷이 하나가 아니라면 어떻게 해야할까?? 다음과 같은 extension을 만들어서 쓰는게 깔끔할것같다!!!!! extension JSONDecoder { /// Assign multiple DateFormatter to dateDecodingStrategy /// /// Usage : /// /// decoder.dateDecodingStrategyFormatters = ..
chp747.tistory.com/54
baked-corn.tistory.com/45
"Domain=NSURLErrorDomain Code=-999 "cancelled"" 에러가 계속되어서 엄청 스트레스 받았는데..(처음에는 헤더 문제인줄 알았다) private var cancellable: AnyCancellable? // 이렇게 작성해줘야함!!!! let m = buildHomeModel(customerId: "CUSTOMER000000000017") // Create a DataTaskPublisher let postUserPublisher = try! postBuildHome(body: m) // Use the sink Subscriber to complete the Publisher -> Subscriber pipeline cancellable = postUserPublisher..