프로젝트를 하는 도중 emoji를 imageView에 랜덤으로 받아줘야하는 테스크를 받았다.
여러 emoji를 스트링값으로 배열을 받아 랜덤 처리하는 방식은 생각해냈지만, 이를 이미지로 그려주는 함수를 애플에서 제공해주는지는 몰랐다.
String타입의 이모지를 Image 타입으로 전환
버튼을 누르면 해당 이미지를 랜덤으로 ImageView에 보여주기
extension + string
funcemojiToImg()->UIImage?{letsize=CGSize(width:100,height:100)// 내가 원하는 이미지 사이즈UIGraphicsBeginImageContextWithOptions(size,false,0)UIColor.clear.set()letrect=CGRect(origin:.zero,size:size)UIRectFill(CGRect(origin:.zero,size:size))(selfasAnyObject).draw(in:rect,withAttributes:[.font:UIFont.systemFont(ofSize:100)])letimage=UIGraphicsGetImageFromCurrentImageContext()UIGraphicsEndImageContext()returnimage}
프로젝트를 진행하다보니 앱을 실행시킬때마다 엄청 지저분한 메시지들이 우두두두두 쏟아지는 것을 볼 수 있었다.
[LayoutConstraints] Unable to simultaneously satisfy constraints.
Probably at least one of the constraints in the following list is one you don't want.
Try this:
(1) look at each constraint and try to figure out which you don't expect;
(2) find the code that added the unwanted constraint or constraints and fix it.
(
"<NSLayoutConstraint:0x60000012ba20 UIView:0x7feb9bc4e7c0.width == 335 (active)>",
"<NSLayoutConstraint:0x60000012be30 H:[UIView:0x7feb9bc4e7c0]-(20)-| (active, names: '|':UITableViewCellContentView:0x7feb9bc1e4e0 )>",
"<NSLayoutConstraint:0x60000012bd90 H:|-(20)-[UIView:0x7feb9bc4e7c0] (active, names: '|':UITableViewCellContentView:0x7feb9bc1e4e0 )>",
"<NSLayoutConstraint:0x60000016c690 'fittingSizeHTarget' UITableViewCellContentView:0x7feb9bc1e4e0.width == 414 (active)>"
)
Will attempt to recover by breaking constraint
<NSLayoutConstraint:0x60000012ba20 UIView:0x7feb9bc4e7c0.width == 335 (active)>
Make a symbolic breakpoint at UIViewAlertForUnsatisfiableConstraints to catch this in the debugger.
말 그대로 레이아웃이 꺠졌다는 의미이다.
막상 앱을 실행시켰을때는 에러도 없고, 눈에 보이는 레이아웃에는 문제가 없어보이지만 실제로는 고쳐야할 요소가 있다는 의미이다.
레이아웃을 쉽게 고치는 방법에 대해서 알아봅시다.
1. view Hierarchy 를 캡쳐
여기서 맨 마지막 아이콘을 누르게 되면 스토리보드의 화면이 아래와 같이 변한다.
보다 정교하게 UI를 분석할 수 있으며, 아래 네비게이터를 보면 계층구조와 제약조건을 볼 수 있게 된다.
만약 여기서 중복되어 적용된 레이아웃이 있다면 오른쪽에 보라색으로 느낌표가 뜰 것이다.
2. breakPoint 사용
xib나 storyboard같은 UI Builder 사용하여 만들면, 레이아웃이 중복적용되어있거나 빠져있는 경우에 경고를 날려준다. 하지만, 코드로 구성할 때는 이를 알 수 없고 아까 위에서처럼 단순히 메시지만 던져주게 된다.
이때 중점적으로 볼 메시지는 아래와 같다.
Make a symbolic breakpoint at UIViewAlertForUnsatisfiableConstraints to catch this in the debugger.
위 아이콘을 클릭해 브레이크포인트를 만들어봅시다. 우리가 만들 브레이크 포인트는 symbolic breakpoint입니다.
+버튼을 눌러 symbolic breakpoint를 누르고 심볼 부분에 UIViewAlertForUnsatisfiableConstraints를 작성해줍니다.
이후 앱이 깨지는 부분으로 돌아가 고쳐주면 됩니다 :)
3. WTF Auto Layout
마지막으로는 WTF Auto Layout입니당.
왓더..ㅍ..이 아닌 Why The Failure의 약자로 여기로 들어가보면 바로 실행해볼 수 있다.
혹시 앱을 실행시켰는데 광고가 제대로 된 사이즈로 나오지 않았다면, 셀에 제대로 제약을 걸어주었는지 확인합시다.
uiView를 올리고 해당 뷰에 높이 설정을 제대로 해주었다면 사실 문제없이 광고가 정 사이즈로 나오겠지만, uiView를 띄우지 않고 addSubview를 했다면 셀높이에 대한 제약 조건을 걸어주어야 합니다 :)
앱 등록과 광고단위 ID 발급이 완료된 후, 다음 단계의 안내에 따라 AdFit SDK를 설치한다.
2. SDK 설치하기
pod 'AdFitSDK' > pod install
3. 프로젝트 설정
ATS(App Transport Security)처리
iOS 9부터 ATS(App Transport Security) 기능이 기본적으로 활성화 되어 있기 때문에 암호화된 HTTPS 방식의 통신만 허용됩니다. AdFit SDK는 ATS 활성화 상태에서도 정상적으로 동작하도록 구현되어 있으나, 광고를 통해 노출되는 광고주 페이지는 HTTPS 방식을 지원하지 않을 수도 있기 때문 에 아래의 사항을 앱 프로젝트의 Info.plist 파일에 적용하여 주어야 한다.
제 블로그에서는 단순히 파이어베이스에서 fcm 연동하는 부분만 정리하였습니다.
애플 개발자 홈페이지에서 인증서를 발급받는 부분은 정리되어있지 않습니다 :)
ios 파이어베이스 연동하기
파이어베이스 콘솔 > [settings] > [클라우드 메시징]
APNs 파일을 업로드 하기위해 애플에서 발급받은 p8 파일을 같이 업로드 해줍니다.
뿐만 아니라 애플에서 발급받은 키ID와 팀ID를 입력합니다.
그리고 이제 xcode로 돌아옵니다.
Xcode > target > Push Notifications 추가
xcode로 돌아와 프로젝트의 target으로 들어가 + 버튼을 누르고 Push Notifications을 추가해줍니다.
그리고 Podfile에 아래를 추가해줍니다.
pod 'Firebase/Core'
pod 'Firebase/Analytics'
pod 'Firebase/Messaging'
이후 pod install 하는 것은 잊지마시구용!
App Delegate
pod install이 끝나면 app delegate로 돌아옵니다.
그리고 아래 코드를 추가해줍니다.
(import Firebase와 import UserNotifications 꼭 해주세요!)
funcapplication(_application:UIApplication,didFinishLaunchingWithOptionslaunchOptions:[UIApplication.LaunchOptionsKey:Any]?)->Bool{// Override point for customization after application launch.FirebaseApp.configure()UNUserNotificationCenter.current().delegate=selfMessaging.messaging().delegate=selfletauthOptions:UNAuthorizationOptions=[.alert,.badge,.sound]UNUserNotificationCenter.current().requestAuthorization(options:authOptions,completionHandler:{(_,_)in})application.registerForRemoteNotifications()returntrue