티스토리 뷰

iOS

iOS ) removingPercentEncoding

Zedd0202 2020. 9. 28. 13:18
반응형

 

안녕하세요 :) Zedd입니다.

기록용 글입니다!

 

~ 상황 ~

1. TextView에서 URL이 있으면 링크화(?)가 되고, 누르면 이동되는 기능을 추가해야했다.

2. 이 기능은 UITextView가 기본적으로 지원.

3. dataDetectorTypes을 link로 해주고, shouldInteractWith URL메소드를 구현해주면 된다.

4. www.tistory.com/안녕하세요? 라는 URL이 있다고 가정해보자.

여기서 "안녕하세요?" 부분을 얻어와서 api호출을 해야한다.

 

# 문제

API호출 부분에서,

urlString.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed)

이런식으로 해주고 있음. 

한글이나 스페이스가 들어간 string을 URL로 만들려고 하면 nil이 나오기 때문에, encoding을 해주는 것. 

(zeddios.tistory.com/281 참고)

 

여기까진 문제가 별로 없어보지만, 

// www.tistory.com/안녕하세요? 탭.

func textView(_ textView: UITextView, shouldInteractWith URL: URL, in characterRange: NSRange, interaction: UITextItemInteraction) -> Bool {
    print(URL.absoluteString)
    return false
}

www.tistory.com/안녕하세요? 탭 후 위 메소드가 불리는데, 여기서 absoluteString을 찍어보면 

www.tistory.com/안녕하세요? 가 나오는게 아니라

http://www.tistory.com/%EC%95%88%EB%85%95%ED%95%98%EC%84%B8%EC%9A%94%3F

이렇게 인코딩된 문자열이 나오게 된다. absoluteString의 기본적인 기능같다. 

하지만 위에서 말했듯이, api 호출 부분에서 

urlString.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed)

이 코드를 호출하게 되는데, 인코딩 된 문자열을 한번 더 인코딩하게 되어 

내가 원하는 결과가 나오질 않았다. 

 

# 해결

해결방법은 removingPercentEncoding을 이용하는 것이다.

removingPercentEncoding은 percent-encoded 시퀀스를 일치하는 UTF-8문자열로 대체해주는 거다.

코드로 보면

let string = "http://www.tistory.com/안녕하세요?"
let encodedString = "http://www.tistory.com/%EC%95%88%EB%85%95%ED%95%98%EC%84%B8%EC%9A%94%3F"
encodedString.removingPercentEncoding // "http://www.tistory.com/안녕하세요?"

이런식이 된다. 

removingPercentEncoding을 아무 String에 때려도 되는것은 아니다.

removingPercentEncoding의 문서에 보면, 

percent-encoded된 문자열에서만 이 메소드를 호출하라는 말이 있다.

percent-encoded가 아닌 문자열에서 이 메소드를 호출하면,

percent character가 percent-encoded시퀀스의 시작으로 잘못 해석 될 수 있다는 것. 

"http://www.tistory.com/%안녕하세요?".removingPercentEncoding // nil ‼️‼️

그러니 아무 string에나 removingPercentEncoding을 때리지 말자. 

shouldInteractWith에 

func textView(_ textView: UITextView, shouldInteractWith URL: URL, in characterRange: NSRange, interaction: UITextItemInteraction) -> Bool {
    URL.absoluteString.removingPercentEncoding
    return false
}

Q : 이렇게 해서 해결은 했는데...그럼 URL자체에 %가 들어가있으면 어떻게해..?? 

www.tistory.com/%abc 이런거;;;

www.tistory.com/%abc.removingPercentEncoding ⇒ nil

A : 일단은 이거는 서비스쪽에서 처리가 되고있고..미디엄이나 다른곳들도 %abc이런 URL은 안나오더라구요?

미디엄은 제목이 URL 쿼리로 들어가는 것 같은데,medium.com/official-podo/개발자와-디자이너를-위한-custom-sf-symbol-만드는-법-374b14448db6 

이런식으로...%ddd%% 뭐 이런식으로 하면 그냥 ddd-(아무 String)이런식으로 나오더라구요.

정확히는 %가 무시되고 주소가 만들어지고 있고, 제 서비스에서도 그렇게 처리되어있길래..

이건 넘어가기로 "나와 합의" 

 

그렇다면 이 다음 생기는 궁금증은..특정 string(ex: www.tistory.com/안녕하세요? ) 이 인코딩 된 상태냐 아니냐를 판단할 수 있나? 였다. => 한번 더 인코딩 하고 싶지 않다. 

내가 못찾는건지;; 딱히 이 string이 인코딩 된 상태인지 알 수 있는 방법이 없는 것 같았다. 

이런 방법도 있는 것 같은데;; removingPercentEncoding를 아무데서나 때리고싶지 않아 이 방법은 쓰루. 

그래서 일단은...string을 가지고 URL을 만들 수 있으면 넘어가고, URL을 만들 수 없으면 encoding을 하는식으로 했다. 

let encodedURL: String = {
    if URL(string: url) != nil {
        return url
    } else {
        return url.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed)
    }
}()

대충 이런식;;

흔히 개발자들이 말하는 "elegant"한 방법은 아닌 것 같은데,

애초에 해당 string이 valid한 주소이고, 그 String을 URL로 만들 수 있다면 encoding을 안해도 되는거 아닌가? 에서 나온 코드이다. 

혹시 String이 encoding된 상태인지...판별하는 "elegant"한 방법이 있다면 댓글 달아주면 감사하겠습니다. 

반응형