이름으로 쿠키 가져오기 in Javascript

function getCookie(name) {
  var value = "; " + document.cookie;
  var parts = value.split("; " + name + "=");
  if (parts.length == 2) return parts.pop().split(";").shift();
}

Swift에서도 쿠키를 가져 올 수 있으나 가급적 웹뷰에 대한 부분은 Javascript에 의존하기로 합시다.

위 Javascript를 아래와 같이 적용하면 필요한 쿠키를 손쉽게 가져올 수 있습니다.

webView.evaluateJavaScript("function getCookie(name) {  var value = \"; \" + document.cookie;  var parts = value.split(\"; \" + name + \"=\");  if (parts.length == 2) return parts.pop().split(\";\").shift();}; getCookie('basket_cnt');") { (object, error) in
    print(object)
}

 

Advertisements

WKWebView 에서 Ajax 통신을 감지하는 방법. feat. Javascript

UIWebView 시절에도 그랬지만, WKWebView 에서도 Ajax 통신을 감지할 수 없습니다.

WKWebView 에서 추가된

@available(iOS 8.0, *)
optional public func webView(webView: WKWebView, decidePolicyForNavigationResponse navigationResponse: WKNavigationResponse, decisionHandler: (WKNavigationResponsePolicy) -> Void)

에서는 <iframe /> 통신(완료)은 감지 가능하지만 역시 Ajax 통신을 감지할 수 없습니다.

웹은 Swift의 전문 분야가 아닙니다. 웹의 전문 분야인 Javascript에게 도움을 요청합시다.

@available(iOS 8.0, *)
optional public func webView(webView: WKWebView, didFinishNavigation navigation: WKNavigation!)

didFinishNavigation에서 일반 통신이 종료되는 시점을 감지하여 Ajax 통신을 감지하는 자바스크립트 명령을 삽입합니다.

self.webKit.evaluateJavaScript("_send = XMLHttpRequest.prototype.send; XMLHttpRequest.prototype.send = function() { alert('ajax:'); var callback = this.onreadystatechange; this.onreadystatechange = function() { if (this.readyState === 4 &amp;amp;&amp;amp; this.status === 200) { alert('ajaxDone'); } callback.apply(this, arguments); }; _send.apply(this, arguments); }; 'script inserted';", completionHandler: { (object, error) in
    print(object)
})

위 명령은 Ajax 를 관장하는 XMLHttpRequest의 send() 메소드를 오버라이딩하여 Ajax 통신 상태를 앱에 전달하여 주기 위한 자바스크립트입니다.

_send = XMLHttpRequest.prototype.send;
XMLHttpRequest.prototype.send = function() {
    alert('ajax');
    var callback = this.onreadystatechange;
    this.onreadystatechange = function() {
        if (this.readyState === 4 && this.status === 200) {
            alert('ajaxDone');
        }

        callback.apply(this, arguments);
    };

    _send.apply(this, arguments);
};

Javascript와 WKWebView간의 효과적인 통신 방법은 WKUserContentController를 이용하는 방법이 있습니다. 하지만 이것은 다음에 기회가 되면 다시 설명 드리기로 하고 여기에서는 간단하게 Javascript의 alert()과 WKUIDelegate의

@available(iOS 8.0, *)
optional public func webView(webView: WKWebView, runJavaScriptAlertPanelWithMessage message: String, initiatedByFrame frame: WKFrameInfo, completionHandler: () -> Void)

를 이용하는 방법을 사용하겠습니다. 위 protocol은 WKWebView에서 alert() 자바스크립트가 작동되면 호출됩니다.

위 자바스크립트를 이용하여 Ajax(XMLHttpRequest)가 작동하면 alert(‘ajax’); 를 호출 하도록 했고, 통신이 정상적으로 완료 되면 alert(‘ajaxDone’); 를 호출 하도록 하였습니다.

Swift에서는 아래와 같이 각 메세지를 받아서 분기 처리를 할 수 있습니다.

func webView(webView: WKWebView, runJavaScriptAlertPanelWithMessage message: String, initiatedByFrame frame: WKFrameInfo, completionHandler: () -> Void) {
    if message == "ajax" {
        // Ajax 통신 시 웹뷰의 URL을 변경 시키는 경우가 있으므로 이를 확인.
        // Ajax 통신이 이루어지는 URL과는 다름.
        print(webView.URL?.absoluteString)
        completionHandler()

        return
    }
    else if message == "ajaxDone" {
        // Ajax 통신으로 달라 진 HTML (DOM) 을 확인.
        self.webKit.evaluateJavaScript("document.documentElement.outerHTML", completionHandler: { (object, error) in
            print(object)
        })
        completionHandler()

        return
    }

    // UIAlertController 사용 message 내용 띄우기.

    completionHandler()
}

이제 WKWebView는 Ajax를 포함한 모든 통신을 감지할 수 있게 되었습니다.

단순히 웹뷰에 웹을 보여 주는 한계에서 벗어 나 앱의 제어권을 더 넒힌 하이브리드앱의 제작이 가능해졌습니다.

구글 포토(Google Photos)에 올려진 사진, 컴퓨터로 전체 다운로드 받는 방법.

구글 포토는 무제한(고품질 사이즈 변환) 용량과 라이브 포토(아이폰 6s이상)를 지원하는 막강한 사진 클라우드 서비스입니다.
그러나 사진은 개개인에게 있어 매우 중요한 것이기 때문에 클라우드 서비스에 의존 했다가 사진을 다 날려 버리지 않을까? 다른 클라우드 서비스를 이용할때 옮길 수 있나 고민이 많이 될 것입니다.

구글은 이런 사용자들의 고민을 위해 모든 사진을 통째로 컴퓨터에 다운로드 받을 수 있는 서비스를 제공하고 있습니다.

https://takeout.google.com/settings/takeout

구글 포토 뿐 아니라 구글에 가입하여 이용 중인 서비스는 모두 위 URL에서 Export  할 수 있습니다.
사실 위 서비스를 찾게 된 것은 Google Play Music에 업로드 한 음원들을 다운로드 할 방법이 없을까 해서 찾았던 것인데, 음원이라는 특성 때문인지 해당 서비스는 전체 다운로드 서비스를 제공하지 않네요. music.google.com에서도 다운로드 횟수는 제한되어 있으므로 구글 뮤직 서비스를 이용하는 분은 꼭 필히 음원을 별도로 보관하셔야 겠습니다.

1

https://takeout.google.com/settings/takeout 으로 접속하면 위와 같은 화면을 보실 수 있습니다. 여러개의 구글 계정을 이용하신다면 우측 상단의 프로필 사진을 눌러 Export하려는 계정이 제대로 선택되어 있는 지 확인을 하셔야 합니다.

Google Photos만 다운로드 할 것이기 때문에 ‘Select None’으로 전체 선택을 해제해 줍니다.

2

Google Photos만 선택 후 ‘Next’

3

대부분의 경우 Google Photos에서 다운로드 받을 파일은 용량이 매우 크기 때문에 자체적으로 압축을 하는데 압축이 완료되면 압축 파일을 다운로드 할 수 있는 URL을 해당 이메일 계정으로 보내 줍니다.

Delivery method에서는 이 외에 추가적인 선택을 할 수 있도록 해주는데

  • Add to Drive : 구글 드라이브에 압축 파일들을 추가 합니다.
  • Add to Dropbox : 드롭박스에 압축 파일들을 업로드 합니다.
  • Add to OneDrive : 마이크로소프트 원드라이브에 압축 파일들을 업로드 합니다.

위 옵션들을 선택하지 않을 거면 그냥 ‘Send download link via email’을 선택하세요.

마지막으로 ‘Create archive’를 누른 후 압축 후 올 이메일을 기다리시면 됩니다.
이메일로 다운로드 링크를 제공하므로 해당 링크에서 파일들을 전부 다운로드 받으면 끝!

전 총 12.4GB로 2기가씩 나눠서 총 7개의 압축 파일이 생성되었네요.

Xbox One 골드 회원 무료 게임 2016/06/16 ~ 07/15 The Crew 소개.

Xbox Live Gold 회원에게 무료로 제공되는 6월 두번째 Xbox One 게임은 The Crew 입니다.
2014년 UbiSoft에서 출시한 오픈 월드 온라인 레이싱 게임입니다.
실제로 해보면 GTA 5에서 레이싱 부분만 떼어낸 듯한 느낌인데 오픈 월드라는 장르적 특성 때문이 아닐까 합니다.

그럼 오픈 월드로 레이싱 외 북미 전역을 다닐 수 있고 차를 수집하고 파츠 업그레이드를 하는 재미를 얻을 수 있는 The Crew를 잠시 살펴 보겠습니다.

Sat_Jun_18_21-10-01_UTC%2B0900_2016

게임 시작과 함께 주인공은 경찰에게 쫓기고 있습니다.

Sat_Jun_18_21-10-35_UTC%2B0900_2016

저 빨간 트럭을 타고 경찰을 따돌려야 합니다. 우측 하단의 미니맵을 보며 체크포인트만 따라가면 쉽게 경찰이 따돌려 집니다. 스토리 상 진행되는 내용이기 때문에 실패하지 않죠.

경찰을 따돌리고 차를 갈아 탄 주인공은

Sat_Jun_18_21-10-56_UTC%2B0900_2016

바로 이 차로 레이싱에 참가합니다.

Sat_Jun_18_21-33-14_UTC%2B0900_2016

레이싱에서 이긴 주인공에게 형이 다가와서 차로 어딘가로 태워 달라 합니다.
형의 부탁이니 당연히 들어줍니다.

Sat_Jun_18_21-34-59_UTC%2B0900_2016

게임 진행 중 목적지(Waypoint)는 우측 하단 미니맵에서도 길이 표시 되지만 게임 화면에서도 차량 위로 표시가 되기 때문에 오픈월드 특성상 길이 정해져 있지 않지만 목적지를 쉽게 찾아 갈 수 있습니다.

Sat_Jun_18_21-35-34_UTC%2B0900_2016

목적지에 도착한 형은 뒤이어 나타난 누군가와 대화를 합니다.

Sat_Jun_18_21-35-56_UTC%2B0900_2016

그리고

Sat_Jun_18_21-36-31_UTC%2B0900_2016

돌아오는 형을….

차에 탄 누군가가 총으로 쏴 버립니다.

Sat_Jun_18_21-36-52_UTC%2B0900_2016

총을 버리고 떠나는 범인.

Sat_Jun_18_21-37-25_UTC%2B0900_2016

쓰러진 형을 안고 절규하는 주인공은
곧이어 나타난 FBI 요원에게 형의 살인범으로 체포됩니다.

Sat_Jun_18_21-40-26_UTC%2B0900_2016

바로 이 새끼. 이 새끼가 나쁜놈이죠.

주인공은 꼼짝없이 누명을 쓰고 감옥에 갇힙니다.

Sat_Jun_18_21-40-54_UTC%2B0900_2016

5년 후 Zoe라는 여자가 찾아 옵니다. 이 여자는 형의 살인범이 누구인지 알려 주고 그와 연루된 부패 FBI 요원이 흑막임을 알려 줍니다.

Sat_Jun_18_21-43-50_UTC%2B0900_2016

바로 저 새끼. 저 새끼가 나쁜 새끼.

Zoe도 FBI요원입니다. 그녀는 부패 FBI 요원을 체포하고 불법 레이싱, 무기 거래, 도박 등을 저지르는 범죄 조직을 소탕하길 원합니다.
바로 그러기 위해 주인공에게 협조를 요구하기 위해 온 것이었죠.
주인공은 그렇게 형의 복수를 하기 위해 정의 구현을 위해 5년만에 세상 밖으로 나옵니다.

우선 주인공은 레이싱으로 범죄 조직에 침투하기 위해 차를 구매합니다.

처음에 게이머는 4종의 차 중 하나를 구매할 수 있는데, The Crew는 실제 제조사의 실제 차량이 나옵니다. 저는 4종 중 디자인이 가장 마음에 든 닛산 차량을 구매 했습니다.

Sat_Jun_18_21-47-07_UTC%2B0900_2016

오! 예뻐!

차량을 구매한 후 파츠 개조를 할 수 있는 곳으로 이동합니다.

Sat_Jun_18_21-47-37_UTC%2B0900_2016

게임 내의 이동은 이런식입니다.

  • Set waypoint : 웨이포인트를 찍어서 직접 이동.
  • Fast travel : 근처로 바로 이동.
  • Enter/Play : 해당 이벤트 실행.

참고로 직접 이동 시 보행자를 차량으로 치려 하면 GTA 시리즈와 달리 칠 수 없습니다. 보행자들이 스파이더맨급 인지 능력과 순발력으로 피해 버립니다. ㅎㅎ
그리고 GTA와 마찬가지로 위험한 운전을 하면 경찰에 추격을 받게 되는데 경찰의 추격이 위협적이지 않고 잡혔을때의 핸디캡도 크지 않기 때문에 게임에서 큰 요소가 되진 않습니다.

Street Tuner로 이동하면 차량을 커스텀할 수 있습니다. 처음이기 때문에 기본적으로 모든 파트가 담긴 Starter Kit을 제공받습니다.

칼라도 변경할 수 있는데 스포츠카는 역시 빨강이죠.

Sat_Jun_18_21-47-59_UTC%2B0900_2016

각 파츠는 메인스토리/서브미션 등 레이싱에서 승리하면 업그레이드 할 수 있습니다.

Sat_Jun_18_21-48-28_UTC%2B0900_2016

그 다음 이동하는 곳은 ‘본부'(HQ Detroit)입니다. 드디어 튜토리얼이 끝났군요.

본부에서는 차량, 콜렉션, 진행도, 파트너 등에 대한 정보를 살펴 볼 수 있는데.

본부의 Workshop에서는 차량의 자세한 부분들을 살펴 볼 수 있습니다.

Sat_Jun_18_21-48-41_UTC%2B0900_2016

고급 차량의 근사한 내부도 볼 수 있으며 (사실 의자를 살펴 보는 것입니다.)

Sat_Jun_18_21-48-51_UTC%2B0900_2016

범퍼등 차량의 구성 요소를 하나씩 뜯어서 볼 수 있고

Sat_Jun_18_21-49-29_UTC%2B0900_2016

겉을 들어내고 파츠도 구경이 가능합니다. 차덕후 들에겐 충분히 흥분 시킬 만한 요소일 것 같네요.

Sat_Jun_18_21-49-40_UTC%2B0900_2016

Collection에서는 수집한 차량들을 모아 볼 수 있습니다.

Sat_Jun_18_21-50-28_UTC%2B0900_2016

그리 많은 차량이 존재하는 것은 아닙니다. The Crew는 실제 브랜드와 차량이 나오는데 라이센스 비용 때문이 아닐까 싶네요. 오픈월드 특성상 제작 비용도 많이 들었을 테니까요.

Sat_Jun_18_21-50-39_UTC%2B0900_2016

Progression에서는 메인스토리 진행도를 확인할 수 있습니다.

Sat_Jun_18_21-50-54_UTC%2B0900_2016

메인스토리 컷씬들도 다시 볼 수 있습니다.

Sat_Jun_18_21-51-03_UTC%2B0900_2016

그 외에도 서브 미션을 통해 매니아 레이싱 유저들을 만족 시킬만한 여러 서브 게임들을 제공합니다.

몬스터 트럭을 몰아 볼 수도 있고

Sat_Jun_18_21-51-20_UTC%2B0900_2016

슈퍼카를 이용한 드래그 레이싱도 즐길 수 있습니다.

Sat_Jun_18_21-51-30_UTC%2B0900_2016

하지만 무엇보다 북미 전역을 차량을 이용해 달려 볼 수 있는 오픈월드라는 점이 The Crew의 가장 큰 특성일 것 같네요.

슈퍼카는 좋아하지만 레이싱 자체를 좋아하지 않기 때문에, 레이싱 유저들의 입장에선 어떤 게임인지에 대해선 쓰질 못한 것 같네요.

하지만 북미 전역을 다닐 수 있다는 점, 실제 브랜드/실제 자동차, 차량을 내부 파츠까지 자세히 살펴 볼 수 있다는 점에서 레이싱 유저들이 한번쯤은 접해볼만한 게임일 것이라 생각합니다

*본 게임은 GameSpot에서 10점 만점에 5점을 받았습니다.

Xbox 360 골드 회원 무료 게임 2016/06/16 ~ 06/30 XCOM Enemy Unknown (한글자막지원) 추천.

Xbox Live Gold 회원에게 무료로 제공되는 6월 두번째 Xbox 360 게임은 XCOM Enemy Unknown 입니다
최근 출시한 XCOM 2의 공식 전작이며 1993년 MS-DOS용으로 출시했던 게임의 리부트 버전이죠. (원래 시리즈는 X-COM 리부트 하면서 – 를 빼버림.)
간단히 게임 소개를 하자면 외계인의 침공에 맞서 전세계가 힘을 모아 XCOM 부대를 창설합니다.
바로 이 XCOM의 지휘관이 되어 전 세계를 외계인으로부터 지키는 것이 내용입니다.
(하지만 XCOM 2의 스토리로 인해 무엇을 해도 미래는 정혀져 있다….)

*Xbox 360은 일반적인 방법으로는 스크린샷을 찍을 수 없어서 아래의 스크린샷은 모두 구글 검색으로 가져온 것임을 밝힙니다.
*Xbox One 하위 호환으로 본 게임은 Xbox One에서도 플레이할 수 있습니다.

xcom_eu_360_m

게임 진행은 부대전술 턴 방식 전투가 메인인데.
전투에서 얻은 외계인 무기와 시체를 이용하여 연구 개발하여 전투력을 올릴 수 있습니다.
병사들은 아무리 열심히 키워도 죽으면 끝이지만… 남는 것은 기술뿐.

d0132254_514aa44521d51

게임 난이도는 쉬움이나 보통을 추천 드립니다. 흔히 하던 SRPG 게임에 익숙하고 잘하였다고 클래식을 선택하면 곤란합니다. 클래식이라는 건 도스시절 오리지날 엑스컴의 난이도를 말하는 것인데.
당시 아재들이 피눈물을 흘렸다는 것을 생각한다면 절대 추천하지 않습니다.
보통 난이도까지는 사용자의 승리를 위해 내부적으로 보정이 되어 있습니다. 사실 보통은 쉬움, 쉬움은 매우쉬움 난이도 인 것이죠.
근데 그래도 보통 난이도도 어렵습니다. 갈수록 어려워집니다.
그렇다면… 클래식은?

게임을 시작하게 되면 민간인들이 외계인들의 공격에 학살당하는 모습이 나오고.
부관이 나와 상황을 설명합니다.

Central_Officer_Bradford

이 인물은 XCOM 2에서도 등장하는 중요인물이며 끊임없이 일거리를 던지고 잔소리를 하는 인물이니 가능한 빨리 익숙해 집시다. ㅎㅎ

자 그럼 부관의 명령을 받고 출동!!!! 하면 전투에 대한 튜토리얼이 시작됩니다.

d0132254_514aa4541c5da

한 턴에 각 유닛은 두번의 행동만을 할 수 있다는 것과 엄폐의 중요성에 대해 설명해 줍니다.

XCOM(EU)_DeltaSquad_survivor

멋지게 외계인들을 사살하고 전투 튜토리얼을 마칩시다.

전투 튜토리얼을 마치게 되면 발음이 특이한 여자 과학자를 만나게 됩니다.

aab431132f9d3a747cd4225e0b768410

그녀는 외계인들의 무기와 시체를 가지고 연구를 합니다.

xcomgame2012-10-1321-18-48-901

연구실에서 연구된 장비는 기술실에서 생산하여 각 병사들에게 제공할 수 있습니다.
S.C.O.P.E를 장착하게 되면 수류탄을 장비할 수 없습니다. 이유는 잘 모르겠지만 어쨋든 그렇습니다.
그러니 쓸데 없이 돈 낭비하지 말고 적당히 생산합시다.

 

전투 튜토리얼을 마치고 얻은 당신의 첫 일병은

f0059347_5062a036ce77c

이렇지만.

계속 연구 개발하다 보면.

frame_0002_1280w

이런 장비들로 무장한 신병을 가질 수 있습니다.

그럼. 외계인으로부터 세계를 지켜 주세요. 사령관님.

 

*참고로 XCOM Enemy Unknown은 Xbox 뿐 아니라 iOS(iPhone/iPad), Android, Windows, PS Vita, PS3, 맥(OS X) 등 다양한 플랫폼을 지원하므로 Xbox가 없다고 하더라도 즐길 수 있습니다.

알리익스프레스에서 구매한 무선 충전(qi) 외장 배터리와 아이폰 6s plus 무선 충전하기. 

알리익스프레스에서 $16.99에 산 qi 무선 충전 외장 배터리가 약 3주 만에 도착했습니다.

흔히 안드로이드폰을 충전할때 사용하는 USB 케이블로 충전을 하고,
일반 USB 충전 케이블을 꽂아 기기들을 충전할 수 있고 남은 용량이 표시 되는 건 여타 외장(보조) 배터리와 다를 바 없습니다.
(용량은 6000 mAh)

하지만! 얘는 qi 무선 충전을 지원 한다는 것!

img_0424

사진엔 보이지 않지만 우측에 있는 작은 전원 버튼을 누르면 남은 용량 확인이 가능하고, 무선 충전 모드가 작동 됩니다. 폰을 올려 놓고 전원 버튼만 눌러 주면 무선 충전 시작!

배터리에 외부 전원이 연결된 상태에서는 전원 버튼을 누르지 않아도 무선 충전이 가능합니다.
배터리와 핸드폰을 동시에 충전 가능하고 배터리를 무선 충전 패드로 이용하는 것도 가능한 거죠.

그런데 말입니다.

제가 사용하는 폰은 아이폰 6s plus입니다. qi 무선 충전 기능은 애초에 없죠.
그래서 구입한 것이 바로 qi 무선 충전 패치.

img_0425

사실 qi 무선 충전이 지원되는 외장 보조 배터리를 구매한 이유가 바로 이 패치 때문입니다.
라이트닝 케이블을 꽂는 곳에 꽂아서 사용하는 것이기 때문에 이걸 사용하게 되면 유선 충전이 힘들어 집니다.
처음엔 소형 슬림한 무선 충전 패드를 사서 들고 다닐까 고민 했지만.
아무리 생각해도 너무 불편할 것 같아서 무선 충전 외장 보조 배터리를 사는 것으로 결정했습니다.
슬림 무선 충전 패드가 약 2만원 하므로 금액은 거의 같은 것 같네요.

아래는 실제 무선 충전을 하는 모습입니다.

img_0429img_0428

아이폰 7에서는 qi 무선 충전 기능이 있었으면 좋겠네요.
참고로 qi는 무선 충전 국제 표준 방식입니다.
애플에서 무선 충전 기능을 넣어도 독자 규격이면 가지고 있는 무선 충전 관련 장비들은 쓸모가 없어 지죠. 그럴 일은 없었으면 좋겠지만…

Optional – ?와 !를 이해 하자.

Objective-C와 Swift의 차이 중 하나는 다이나믹 형변환이 없어지며 자료형이 매우 빡빡해 졌다는 것이다.

빡빡한 자료형에, 개발자들이 품자 마자 풀려 버렸던 의문과 답은 바로

“그럼 null(nil)은 어떻게 넣는데?” 와
“?(Optional)를 써.” 였다.

그렇다고 단순히 Optional을 ‘nil을 넣을 수 있게 자료형을 선언 하는 녀석’으로 이해하면 곤란한데.
보통 이렇게 이해한 개발자들이 !를 남용하기 때문이다.

!를 남용하게 되는 가장 큰 이유는 ?로 선언된 객체는 사용 전에 항상 확인을 해주어야 한다.
이게 귀찮기 때문에 !를 사용하게 되는데.

왜 컴파일러가 Syntax Check를 할때 ?는 사용 전 확인을 강요하고, !는 그냥 넘기는 지 이해 한다면
자연히 ?와 !의 진짜 차이점을 이해할 수 있다.

 

간단하다.

?는 nil 일 수도 있는 녀석.
!는 nil 일 가능성이 없는 녀석.

Swift로 작성된 iOS 개발 예제를 보면 @IBOutlet은 항상 !으로 선언한다.

@IBOutlet var shareButton: UIButton!

뷰콘트롤러가 선언될 당시엔 해당 변수엔 nil이 담기겠지만 Storyboard에 작성된 View가 로드 되면서 해당 변수엔 뷰객체가 담기게 된다. 그래서 해당 변수는 Optional로 선언되어야 하기에 !가 사용되었다.

그러나 ?가 아니다. !는 남용하지 말라고 했는데 그럼 대부분의 개발자가 사용하고 공식 예제에도 사용하는 위의 경우는 남용인가?

아니다.

정상적으로 개발했다면 해당 변수엔 정상적으로 UIButton 객체가 담겨야 한다. nil 일 가능성이 없는 녀석이기 때문에 !를 사용하는 것이 맞다.

Storyboard에서 제대로 작업하지 않아 shareButton과 UIButton을 제대로 연결 시키지 않았다면 앱은 fatal error를 내뱉고 튕겨 버릴 것이다.

이건 수정해야 할 버그지 ?나 !를 따질 문제가 아니다.

그렇다. 사실 ?와 !를 적절히 구분해서 사용해야 되는 이유는 바로 fatal error때문이다.
?를 사용하여 선언한 변수에 대해 컴파일러가 매번 사용 전 확인을 하라고 강제 하는 것은 fatal error를 막기 위해서이다.

그래서 ?는 서버와의 통신이나 사용자 데이타 등 nil 일 가능성이 충분히 있는 변수에 사용하는 것이다.

그러나 그렇다고 너무 ?만 사용해도 fatal error를 내뱉어 즉시적으로 개발상 문제를 파악할 수 있는 부분도 그냥 넘어 가거나 사용전 확인 코드 때문에 코드가 너무 복잡해 지는 등의 문제가 있기 때문에.

개발상 최선의 판단으로 ?와 !를 적절히 사용하는 것이 중요하다.