{"id":504,"date":"2021-07-20T14:40:44","date_gmt":"2021-07-20T05:40:44","guid":{"rendered":"http:\/\/practical.kr\/?p=504"},"modified":"2021-07-20T14:40:44","modified_gmt":"2021-07-20T05:40:44","slug":"swift-swiftui-%ec%a1%b0%eb%8f%84%ec%b8%a1%ec%a0%95%ea%b8%b0-%ea%b0%9c%eb%b0%9c%ea%b8%b0","status":"publish","type":"post","link":"http:\/\/practical.kr\/?p=504","title":{"rendered":"Swift\/SwiftUI &#8211; \uc870\ub3c4\uce21\uc815\uae30 \uac1c\ubc1c\uae30"},"content":{"rendered":"\n<p> Swift\/SwiftUI\ub97c \uc2a4\ud130\ub514 \ud558\uba70 \uac1c\uc778\uc801\uc73c\ub85c \ub450\ubc88\uc9f8 \uc571\uc744 \uc2a4\ud1a0\uc5b4\uc5d0 \uc5c5\ub85c\ub4dc \ud588\uc2b5\ub2c8\ub2e4. <\/p>\n\n\n\n<p>\ucd5c\uadfc\uc5d0 \ud558\ub358 \uc791\uc5c5\uc5d0\uc11c \uc870\ub3c4\ub97c \uce21\uc815\ud574\uc57c \ud560 \uc77c\uc774 \uc788\uc5c8\ub294\ub370 \uce21\uc815\uc218\uce58\ub9cc \ubcf4\uc5ec\uc8fc\ub294 \ubcf4\uc5ec\uc8fc\ub294 \uc571\uc744 \ub2e4\uc6b4 \ubc1b\uc558\ub294\ub370 \uce21\uc815 \uc0c1\ud669\uc5d0 \ub530\ub978 \ub370\uc774\ud130\ub97c \uc800\uc7a5\ud574 \ub450\uace0 \uc2f6\uc5c8\ub294\ub370 \uadf8\uac8c \uc548\ub418\ub354\uad70\uc694. \uadf8\ub798\uc11c \ud558\ub098 \ub9cc\ub4e4\uc5b4 \ubcfc\uae4c \ud558\ub294 \uc0dd\uac01\uc744 \ud588\uc2b5\ub2c8\ub2e4.<\/p>\n\n\n\n<p>\uac1c\uc778\uc801\uc778 \uc694\uad6c\uc0ac\ud56d\uc740 \uc0ac\uc9c4\uacfc \ud568\uaed8 \uce21\uc815\uacb0\uacfc\uac12\uc744 \ubcf4\uad00\ud558\uace0 \ub2e4\uc74c\uc5d0 \ub2e4\ub978 \ud658\uacbd\uc758 \ub370\uc774\ud130\uc640 \ube44\uad50\ud574\uc11c \ubcfc \uc218 \uc788\uc5c8\uc73c\uba74 \ud558\ub294\uac83\uc774\uc5c8\uc2b5\ub2c8\ub2e4.<\/p>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter is-resized\"><img loading=\"lazy\" decoding=\"async\" src=\"http:\/\/practical.kr\/wp-content\/uploads\/2021\/07\/IMG_2713.jpg\" alt=\"\" class=\"wp-image-507\" width=\"248\" height=\"538\"\/><\/figure><\/div>\n\n\n\n<p class=\"has-large-font-size\">\uce74\uba54\ub77c\ubdf0 \ucee8\ud2b8\ub864\ub7ec<\/p>\n\n\n\n<p><a href=\"https:\/\/github.com\/imaginary-cloud\/CameraManager\" target=\"_blank\" rel=\"noreferrer noopener\"> https:\/\/github.com\/imaginary-cloud\/CameraManager<\/a><\/p>\n\n\n\n<p>\uc694\uad6c \uc0ac\ud56d\uc744 \ub9cc\uc871\uc2dc\ud0a4\ub824\uba74 \uc6b0\uc120 \uce74\uba54\ub77c\uac00 \ud544\uc694\ud569\ub2c8\ub2e4. \uadf8\ub9ac\uace0 \uc870\ub3c4\ub97c \uce21\uc815 \ud558\ub824\uba74 \ud504\ub808\uc784\uc744 \ucea1\uccd0\ud574\uc11c \ud604\uc7ac \ud654\uba74\uc758 \uba54\ud0c0\ub370\uc774\ud130\ub97c \uc5bb\uc5b4\uc57c \ud569\ub2c8\ub2e4.  \uce74\uba54\ub77c \ucee8\ud2b8\ub864\uc740 \uc704 \ub9c1\ud06c\uc758 \uc624\ud508 \uc18c\uc2a4\ub97c \uc0ac\uc6a9\ud588\uc2b5\ub2c8\ub2e4. \uc774 \uc624\ud508 \uc18c\uc2a4\ub294 \uc544\uc774\ud3f0 \uce74\uba54\ub77c\ub97c \ub9cc\ub4dc\ub294\ub370 \uaf2d \ud544\uc694\ud55c \uae30\ubcf8\uc801\uc778 \uae30\ub2a5\uc744 \uac16\ucd94\uace0 \uc788\ub294 \uc544\uc8fc \ud6cc\ub96d\ud55c \uc624\ud508\uc18c\uc2a4 \uc785\ub2c8\ub2e4. <\/p>\n\n\n\n<p>\ud558\uc9c0\ub9cc SwiftUI \uae30\ubc18\uc5d0\uc11c \ud504\ub808\uc784\uc744 \ucea1\uccd0\ud558\uae30 \uc704\ud558\uc5ec AVCaptureVideoDataOutputSampleBufferDelegate \uc744 \uc5bb\uc73c\ub824\uba74  \uba87\uac00\uc9c0 \ucd94\uac00\uc801\uc778 \uc791\uc5c5\uc744 \ud574\uc57c \ud569\ub2c8\ub2e4. SwiftUI\uc5d0\uc11c View\uc640 ViewController\ub97c \uc0ac\uc6a9\ud558\ub824\uba74 UIViewControllerRepresentable \ud504\ub85c\ud1a0\ucf5c\uc744 \uad6c\ud604\ud574\uc11c \ub378\ub9ac\uac8c\uc774\uc158\uc744 \uc218\ud589 \ud560 \uc218 \uc788\uc2b5\ub2c8\ub2e4.<\/p>\n\n\n\n<p>\ub378\ub9ac\uac8c\uc774\uc158\uc5d0\uc11c\ub294 \ud504\ub808\uc784\uc774 \ubcc0\ud654\ub420\ub54c\ub9c8\ub2e4 \uce21\uc815\uac12\uc744 \uacc4\uc0b0\ud569\ub2c8\ub2e4.<\/p>\n\n\n\n<p>\ub300\ub7b5\uc758 \ucf54\ub4dc\ub294 \uc544\ub798\uc640 \uac19\uc2b5\ub2c8\ub2e4.<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">\/\/\n\/\/  PreViewController.swift\n\/\/  CamMeter\n\/\/\n\/\/  Created by Park Billy on 2021\/06\/08.\n\/\/\nimport SwiftUI\nimport UIKit\nimport CameraManager\nimport AVFoundation\n\n\nstruct PreViewController: UIViewControllerRepresentable {\n    @State var cameraManager:CameraManager\n    @Binding var lux: Double\n\n    func makeUIViewController(context: Context) -> some UIViewController {\n        let controller = UIViewController()\n            \n        cameraManager.cameraDevice = UserDefaults.standard.integer(forKey: \"device\") == 1 ? CameraDevice.front : CameraDevice.back\n        cameraManager.addPreviewLayerToView(controller.view)\n        cameraManager.cameraOutputMode = CameraOutputMode.videoOnly\n        \n        let output = AVCaptureVideoDataOutput()\n        if ((cameraManager.captureSession?.canAddOutput(output)) != nil) {\n            cameraManager.captureSession?.addOutput(output)\n            let VideoQueue = DispatchQueue(label: \"VideoQueue\")\n            output.setSampleBufferDelegate(context.coordinator, queue: VideoQueue)\n        }\n        return controller\n    }\n    \n    func updateUIViewController(_ uiViewController: UIViewControllerType, context: Context) {\n    }\n\n    class Coordinator: NSObject, AVCaptureVideoDataOutputSampleBufferDelegate {\n        @Binding var lux: Double\n\n        init(lux: Binding&lt;Double>) {\n            _lux = lux\n        }\n\n        func captureOutput(_ output: AVCaptureOutput, didOutput sampleBuffer: CMSampleBuffer, from connection: AVCaptureConnection) {            \n            if let metadata = CMGetAttachment(sampleBuffer, key: kCGImagePropertyExifDictionary, attachmentModeOut: nil) {\n                if let fN = metadata[\"FNumber\"] as? Double {\n                    if let fT = metadata[\"ExposureTime\"] as? Double {\n                        if let speedArr = metadata[\"ISOSpeedRatings\"] as? NSArray {                            \n                            let calValue = UserDefaults.standard.double(forKey: \"calvalue\")                            \n                            let fS = speedArr[0] as! Double\n                            lux = (fN * fN) \/ (fT * fS) * calValue\n                        }\n                    }\n                }\n            }\n            \n        }\n    }\n\n    func makeCoordinator() -> Coordinator {\n        return Coordinator(lux: $lux)\n    }\n\n}\n <\/pre>\n\n\n\n<p class=\"has-large-font-size\">\uc870\ub3c4\uacc4\uc0b0<\/p>\n\n\n\n<p>\uc704\uc758 \ucf54\ub4dc\uc5d0\uc11c \ubcf4\ub2e4\uc2dc\ud53c \ud504\ub808\uc784\ub9cc \uc5bb\uc73c\uba74 \uc870\ub3c4\uacc4\uc0b0\uc740 \uac04\ub2e8\ud569\ub2c8\ub2e4. \uc5bb\uc5b4\ub0b8 sampleBuffer\uc5d0\uc11c Exif \ub370\uc774\ud130\ub97c \ucd94\ucd9c\ud558\uace0 \uadf8\uc911\uc5d0\uc11c FNumber, ExposureTime, ISOSpeedRatings\uc744 \uc774\uc6a9\ud574\uc11c \uac04\ub2e8\ud55c \uacc4\uc0b0\uc2dd\uc744 \ub9cc\ub4e4\uba74 \ub05d\uc785\ub2c8\ub2e4.<\/p>\n\n\n\n<p class=\"has-large-font-size\">\uce98\ub9ac\ube0c\ub808\uc774\uc158<\/p>\n\n\n\n<p>\uacc4\uc0b0 \uacb0\uacfc\ub85c \ub098\uc628 \uc218\uce58\ub294 \uc5bc\ub9c8\ub098 \uc815\ud655 \ud560\uae4c\uc694? \ud655\uc778\ud560 \ubc29\ubc95\uc774 \uc5c6\uc5b4\uc11c \uc544\ub798\uc640 \uac19\uc774 \uc0dd\uae34 \uc870\ub3c4\uacc4\ub97c \uad6c\uc785\ud588\uc2b5\ub2c8\ub2e4.<\/p>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter size-large is-resized\"><img loading=\"lazy\" decoding=\"async\" src=\"http:\/\/practical.kr\/wp-content\/uploads\/2021\/07\/TASI-TA8131TA8133-Digital-Light-Meter-Photography-Digital-Luxmeter-Split-Illuminometer-LuxFc-Photometer-Enviromental-Tester-\u2026-2021-07-20-14-05-41.png\" alt=\"\" class=\"wp-image-513\" width=\"270\" height=\"310\"\/><\/figure><\/div>\n\n\n\n<p>\uadf8\ub9ac\uace0 \uc870\ub3c4\uacc4\uc758 \uacb0\uacfc\uc640 \ub3d9\uc77c\ud55c \ucd9c\ub825\uc774 \ub098\uc62c \uc218 \uc788\ub3c4\ub85d Calibration \ud504\ub9ac\uc14b\uc744 \uc785\ub825 \ud560 \uc218 \uc788\ub294 \uae30\ub2a5\uc744 Settings\uc5d0 \ucd94\uac00 \ud588\uc2b5\ub2c8\ub2e4. \uae30\ubcf8 \ud504\ub9ac\uc14b\uc740 18\uc785\ub2c8\ub2e4. \uc544\ub9c8\ub3c4 \ub354 \uc815\ud655\ud55c \uc870\ub3c4\uacc4\ub97c \uac00\uc9c0\uace0 \uc788\ub2e4\uba74 \uac70\uae30\uc5d0 \ub9de\ub3c4\ub85d \ud504\ub9ac\uc14b\uc744 \uc870\uc815 \ud558\uba74 \ub429\ub2c8\ub2e4. \uce21\uc815\uacb0\uacfc\ub97c \ubcf4\uba70 \uce98\ub9ac\ube0c\ub808\uc774\uc158\uac12\uc744 \uc870\uc815 \ud560 \uc218 \uc788\ub3c4\ub85d \uba54\uc778\ud654\uba74\uc5d0 \uc2ac\ub77c\uc774\ub4dc\ub97c \ubcf4\uc774\ub3c4\ub85d \ud560 \uc218\ub3c4 \uc788\uc2b5\ub2c8\ub2e4.<\/p>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter size-large is-resized\"><img loading=\"lazy\" decoding=\"async\" src=\"http:\/\/practical.kr\/wp-content\/uploads\/2021\/07\/IMG_2708.png\" alt=\"\" class=\"wp-image-515\" width=\"230\" height=\"498\"\/><\/figure><\/div>\n\n\n\n<p class=\"has-large-font-size\">SwiftUI<\/p>\n\n\n\n<p>\uac1c\uc778\uc801\uc73c\ub85c AutoLayout\uc774 \ub3c4\uc785\ub418\uba74\uc11c\ubd80\ud130 iOS \uac1c\ubc1c\uc774 \uc880 \uc7ac\ubbf8\uac00 \uc5c6\uc5b4\uc9c0\uc9c0 \uc54a\uc558\ub098 \ud558\ub294 \uc0dd\uac01\uc744 \ud588\uc2b5\ub2c8\ub2e4. \uadf8\ub9ac\uace0 \uadf8 \uc0ac\uc774\uc5d0 \uc6f9\ud504\ub860\ud2b8 \ud504\ub85c\uc81d\ud2b8\ub97c \ud558\uba74\uc11c HTML, CSS\ub97c \uc54c\uac8c \ub418\uc5c8\uc8e0. \uc544\ubb34\ub798\ub3c4 \uadf8 \ub355\ubd84\uc5d0 SwiftUI\ub97c \ub354 \uc27d\uac8c \ubc1b\uc544 \ub4e4\uc774\uace0 \uc788\ub294\uac8c \uc544\ub2cc\uac00 \ud558\ub294 \uc0dd\uac01\uc744 \ud588\uc2b5\ub2c8\ub2e4. \ucd5c\uadfc \uc4f0\uace0 \uc788\ub294 Flutter\ub3c4 \ub9c8\ucc2c\uac00\uc9c0 \uc778\uac83 \uac19\uad6c\uc694. <\/p>\n\n\n\n<p>iOS \uac1c\ubc1c\uc774 \ub2e4\uc2dc \uc7ac\ubbf8\uc788\uc5b4\uc9c4\uac74 \ubb34\uc5c8\ubcf4\ub2e4\ub3c4 SwiftUI \ub355\ubd84\uc785\ub2c8\ub2e4.<\/p>\n\n\n\n<p class=\"has-large-font-size\">\uc870\ub3c4\uce21\uc815\uae30<\/p>\n\n\n\n<p>\ub450\uc5b4\ub2ec \uc804\uc5d0 SwiftUI \uae30\ubc18\uc73c\ub85c \ucc98\uc74c\ub9cc\ub4e0 <a rel=\"noreferrer noopener\" href=\"https:\/\/apps.apple.com\/us\/app\/\ub0b4\uc5f0\ubd09\uacc4\uc0b0\uae30-\uc2e4\uc218\ub839\uc561-\uc5f0\ubd09\uc21c\uc704\/id1564866857\" data-type=\"URL\" data-id=\"https:\/\/apps.apple.com\/us\/app\/\ub0b4\uc5f0\ubd09\uacc4\uc0b0\uae30-\uc2e4\uc218\ub839\uc561-\uc5f0\ubd09\uc21c\uc704\/id1564866857\" target=\"_blank\">\uc5f0\ubd09\uacc4\uc0b0\uae30<\/a>\ub294 \uc62c\ub838\uc2b5\ub2c8\ub2e4\ub9cc \uc870\ub3c4 \uce21\uc815\uae30\ub294 \uc2e4\uc81c \uce21\uc815\uae30 \uad6c\uc785\ube44 \uc815\ub3c4\ub294 \ub098\uc640\uc57c \ud558\uc9c0 \uc54a\uc744\uae4c \uc2f6\uc5b4\uc11c 1\ub2ec\ub7ec\uc5d0 \uc2a4\ud1a0\uc5b4\uc5d0 \uc62c\ub838\uc2b5\ub2c8\ub2e4. \uc81c\uac00 \uc5ec\u3153\uac00\uc9c0 \uc870\ub3c4\uce21\uc815\uc571\uc744 \ub2e4\uc6b4 \ubc1b\uc544 \ubd24\uc2b5\ub2c8\ub2e4\ub9cc \uc4f8\ub9cc\ud569\ub2c8\ub2e4. ^^;<\/p>\n\n\n\n<p>\uc5ca\uadf8\uc81c \ubc84\uc804\uc744 1.1\ub85c \uc62c\ub9ac\uba74\uc11c \uad11\uc6d0\uac70\ub9ac\ub97c \uc785\ub825\ud558\uba74 \uce78\ub378\ub77c\ub2e8\uc704\ub3c4 \ubcf4\uc5ec\uc8fc\ub3c4\ub85d \uc218\uc815\ud588\uc2b5\ub2c8\ub2e4. \ud55c\uae00\/\uc601\ubb38\/\uc77c\ubcf8\uc5b4 \uc9c0\uc6d0<\/p>\n\n\n\n<p>\ub2f9\uc5f0\ud788! \ud544\uc694\ud558\uc2e0 \ubd84\ub9cc \uc0ac\uc2dc\uba74 \ub429\ub2c8\ub2e4. ^^<\/p>\n\n\n\n<p><a href=\"https:\/\/apps.apple.com\/app\/id1572227924\" target=\"_blank\" rel=\"noreferrer noopener\">https:\/\/apps.apple.com\/app\/id1572227924<\/a><\/p>\n\n\n\n<p>\ubc15\ubcd1\uc77c\/20200720<\/p>\n\n\n\n<p> <\/p>\n","protected":false},"excerpt":{"rendered":"<p>Swift\/SwiftUI\ub97c \uc2a4\ud130\ub514 \ud558\uba70 \uac1c\uc778\uc801\uc73c\ub85c \ub450\ubc88\uc9f8 \uc571\uc744 \uc2a4\ud1a0\uc5b4\uc5d0 \uc5c5\ub85c\ub4dc \ud588\uc2b5\ub2c8\ub2e4. \ucd5c\uadfc\uc5d0 \ud558\ub358 \uc791\uc5c5\uc5d0\uc11c \uc870\ub3c4\ub97c \uce21\uc815\ud574\uc57c \ud560 \uc77c\uc774 \uc788\uc5c8\ub294\ub370 \uce21\uc815\uc218\uce58\ub9cc \ubcf4\uc5ec\uc8fc\ub294 \ubcf4\uc5ec\uc8fc\ub294 \uc571\uc744 \ub2e4\uc6b4 \ubc1b\uc558\ub294\ub370 \uce21\uc815 \uc0c1\ud669\uc5d0 \ub530\ub978 \ub370\uc774\ud130\ub97c \uc800\uc7a5\ud574 \ub450\uace0 \uc2f6\uc5c8\ub294\ub370 \uadf8\uac8c \uc548\ub418\ub354\uad70\uc694. \uadf8\ub798\uc11c \ud558\ub098 \ub9cc\ub4e4\uc5b4 \ubcfc\uae4c \ud558\ub294 \uc0dd\uac01\uc744 \ud588\uc2b5\ub2c8\ub2e4. \uac1c\uc778\uc801\uc778 \uc694\uad6c\uc0ac\ud56d\uc740 \uc0ac\uc9c4\uacfc \ud568\uaed8 \uce21\uc815\uacb0\uacfc\uac12\uc744 \ubcf4\uad00\ud558\uace0 \ub2e4\uc74c\uc5d0 \ub2e4\ub978 \ud658\uacbd\uc758 \ub370\uc774\ud130\uc640 \ube44\uad50\ud574\uc11c \ubcfc \uc218 \uc788\uc5c8\uc73c\uba74 \ud558\ub294\uac83\uc774\uc5c8\uc2b5\ub2c8\ub2e4. \uce74\uba54\ub77c\ubdf0<\/p>\n<div class=\"more-link\">\n\t\t\t\t <a href=\"http:\/\/practical.kr\/?p=504\" class=\"link-btn theme-btn\"><span>Read More <\/span> <i class=\"fa fa-caret-right\"><\/i><\/a>\n\t\t\t<\/div>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"","sticky":false,"template":"","format":"standard","meta":{"_jetpack_memberships_contains_paid_content":false,"footnotes":""},"categories":[13,27,40],"tags":[],"class_list":["post-504","post","type-post","status-publish","format-standard","hentry","category-ios","category-swift","category-swiftui"],"jetpack_featured_media_url":"","jetpack_sharing_enabled":true,"_links":{"self":[{"href":"http:\/\/practical.kr\/index.php?rest_route=\/wp\/v2\/posts\/504","targetHints":{"allow":["GET"]}}],"collection":[{"href":"http:\/\/practical.kr\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"http:\/\/practical.kr\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"http:\/\/practical.kr\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"http:\/\/practical.kr\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=504"}],"version-history":[{"count":11,"href":"http:\/\/practical.kr\/index.php?rest_route=\/wp\/v2\/posts\/504\/revisions"}],"predecessor-version":[{"id":518,"href":"http:\/\/practical.kr\/index.php?rest_route=\/wp\/v2\/posts\/504\/revisions\/518"}],"wp:attachment":[{"href":"http:\/\/practical.kr\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=504"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"http:\/\/practical.kr\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=504"},{"taxonomy":"post_tag","embeddable":true,"href":"http:\/\/practical.kr\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=504"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}