블로그 이미지
개발자로서 현장에서 일하면서 새로 접하는 기술들이나 알게된 정보 등을 정리하기 위한 블로그입니다. 운 좋게 미국에서 큰 회사들의 프로젝트에서 컬설턴트로 일하고 있어서 새로운 기술들을 접할 기회가 많이 있습니다. 미국의 IT 프로젝트에서 사용되는 툴들에 대해 많은 분들과 정보를 공유하고 싶습니다.
솔웅

최근에 받은 트랙백

글 보관함

calendar

    1 2 3 4 5
6 7 8 9 10 11 12
13 14 15 16 17 18 19
20 21 22 23 24 25 26
27 28 29 30 31    

[Swift] Table View 만들기

2015.10.15 05:55 | Posted by 솔웅


원문



테이블 뷰 만들기

1. 새 프로젝트 만들기
Single Page Application 을 선택하고 프로그래밍 언어로 Swift를 선택해서 Project를 만든다.

2. 테이블 뷰 프로퍼티 추가하기
Viewcontroller.swift 에 tableview instance 변수를 추가한다. 

    @IBOutlet
    var tableView: UITableView!


@IBOutlet 속성은 Interface Builder 에 tableView property 를 보이도록 만든다.

3. TableView Delegate 와 DataSource 프로토콜 confirm 하기
UITableViewDelegate 와 UITableViewDataSource  프로토콜을 UIViewController 클래스 정의 바로 다음에 넣는다. (, 로 구분)


class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {

    ...

}



그리고 나서 tableView(_:numberOfRowsInSection:), tableView(_:cellForRowAtIndexPath:) ,tableView(_:didSelectRowAtIndexPath:) 메소드들을 ViewController 클래스 안에 implement 한다. 일단 이 메소드들은 빈 상태로 둔다.


class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {

    ...

    func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return 0
    }

    func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
        return UITableViewCell()
    }

    func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {

    }

}



4. view controller 에 table view를 추가한다.
Component Library에서 Table View를 찾은 후 그 뷰를 끌어서 해당 view에 놓는다.

5. Interface Builder Outlets 와 연결한다.
Referencing Outlet을 dataSource와 Delegate outlet에연결한다.




6. cell class 를 Register 한다.
viewDidLoad 메소드에서 registerClass(_:forCellReuseIdentifier:)를 호출한다.
팁:이 클래스를 얻으려면 self 를 타입하고 tableView를 넣은 다음에 얻으면 된다.

class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {

    ...

    override func viewDidLoad() {
        super.viewDidLoad()

        self.tableView.registerClass(UITableViewCell.self, forCellReuseIdentifier: "cell")
    }

    ...

}



7. Display 할 데이터를 만든다.

스트링 배열로 items 라고 하는 property를 추가한다. 그리고 몇개의 값들을 넣는다.


class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {

    var items: [String] = ["We", "Heart", "Swift"]

    ...

}



8. row 갯수를 세팅한다.

class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {

    ...

    func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return self.items.count;
    }

    ...

}



9. cell을 생성한다.

class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {

    ...

    func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
        var cell:UITableViewCell = self.tableView.dequeueReusableCellWithIdentifier("cell") as UITableViewCell

        cell.textLabel?.text = self.items[indexPath.row]

        return cell
    }

    ...

}



10. cell selection을 처리한다.
Another new thing in Swift is String Interpolation that let’s you add arbitrary code inside a string.


Some examples:

var one = "\(1)" // "1"
var two = "\(1 + 1)" // "2"

var name = "Andrei Puni"
println("my name is \(name) and I heart Swift") // will print "my name is Andrei Puni and I heart Swift"
class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {

    ...

    func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
        println("You selected cell #\(indexPath.row)!")
    }

    ...

}

By now your ViewController class should look like this:

class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
    @IBOutlet
    var tableView: UITableView
    var items: [String] = ["We", "Heart", "Swift"]

    override func viewDidLoad() {
        super.viewDidLoad()

        self.tableView.registerClass(UITableViewCell.self, forCellReuseIdentifier: "cell")
    }


    func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return self.items.count;
    }

    func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
        var cell:UITableViewCell = self.tableView.dequeueReusableCellWithIdentifier("cell") as UITableViewCell

        cell.textLabel?.text = self.items[indexPath.row]

        return cell
    }

    func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
        println("You selected cell #\(indexPath.row)!")
    }
}



UITableViewDelegate

 UITableView 객체를 delegate 하기 위해서는 반드시 UITableViewDelegate 프로토콜을 adopt 해야 한다. 이 프로토콜의 optional 메소드들은 selection들을 관리하고 section heading과 footer들을 configure 하고 각 셀들을 delete하거나 reorder 하는 등의 처리를 하기 위한 delegate 를 가능하게 한다.
 

UITableViewDelegate 프로토콜의 만은 메소드들은 NSIndexPath 객체를 파라미터로 취하고 값을 return 한다. UIKit 는 rowsection index 값을 얻는 것을 가능하도록 하는 NSIndexPath 에 대한 카테고리를 정의한다. 또한 주어진 row, section index로부터 index path를 만드는 것도 정의한다. (indexPathForRow:inSection: method). row들은 section 안에 위치해 있기 때문에 row index 값을 정의하기 이전에 section index 값을 먼저 처리해야 한다.

Configuring Rows for the Table View




UITableViewDataSource

 UITableViewDataSource 프로토콜은 UITableView 객체에 대한 어플리케이션의 데이터 모델을 중개하는 객체에 의해 adopt 된다. 데이터 소스는 테이블 뷰를 구성하고 변경하는데 필요한 정보들을 가지고 있는 테이블뷰 객체를 제공한다.

데이터 모델의 대리인으로서 데이터 소스는 테이블 뷰에 대한 최소한의 정보를 전달한다. 테이블 뷰 객체의 delegate (UITableViewDelegate protocol 을 adopt 한 object)가 그 정보를 제공한다.


이 프로토콜의 required 메소드들은 테이블 뷰에 표시될 cell 들을 제공하고 UITableView 객체에게 section 갯수와 각 section별 row들의 갯수를 알려준다. 데이터 소스는 optional 메소드들을 implement 할 수 있는데 테이블 뷰의 여러가지 부분들을 configure 하거나 row들을 insert, delete, reorder 하는데 사용할 수 있다.

Note

테이블 뷰의 swipe-to-delete 기능을 사용하려면 tableView:commitEditingStyle:forRowAtIndexPath: 메소드를 implement 해야 한다.

많은 메소드들이 NSIndexPath 객체를 파라미터로 받는다. UITableView는 rowsection index 에 대한 값을 얻도록 하는 NSIndexPath 에 대한 카테고리를 정의한다. 그리고 주어진 row, section index로부터 index path 를 구성한다.(indexPathForRow:inSection: class method) 각 index path의 첫번째 index 는 section을 나타내고 그 다음 값은 row 를 나타낸다.

Configuring a Table View


저작자 표시 비영리 동일 조건 변경 허락
신고

TestFlight Beta Testing

2015.09.24 08:50 | Posted by 솔웅


TestFlight Beta Testing


TestFlight Beta Testing 은 iOS 앱을 앱스토어에 release 하기 전에 사용자들에게 미리 테스트 해 볼 수 있도록 한다.
애플 ID 로 이메일을 보내는 방식으로 테스트 할 유저를 1000명까지 초대할 수 있다.







TestFlight 준비하기
Xcode 와 iTunes Connect 를 사용해서 빌드하고 셋업하기
테스터들에게 앱을 테스트하도록 하기 위해 XCode 에서 앱의 beta build 를 업로드 하고 iTunes Connect 에 테스터들의 이름과 이메일 주소를 업로드 한다.
beta app 과 테스터들의 리스트를 셋업하는 방법은 iTunes Connect Developer Guide 에 나와 있고 TestFlight video tutorial에도 설명 돼 있다.




   
TestFlight Beta Tester들 초청하기 


Internal Testers


iTunes Connect 에서 Technical이나 Admin role을 수행하고 있는 팀원 25명에게 beta build를 배포해서 feedback을 받는다.
각 팀원별로 10개의 device를 테스트용으로 사용할 수 있다.

External Testers


준비가 되면 beta tester로 팀원이 아닌 1000명의 사용자를 초청할 수 있다.
외부테스터에게 제공하는 앱은 Beta App Review를 필요로 하고 테스팅하기 전에 전체  App Store Review Guidelines 을 참고하고 이를 준수해야 한다.
Review를 통해서 새로운 버전에서 문제점들을 해결한 보다 완결된 기능을 제공할 수 있다.
한번에 10개의 앱들이 한번에 테스트 될 수 있다. (Internally or Externally)


TestFlight App for iOS


Download on the App Store


테스터를 초대할 때마다, 테스터들은 beta tester 그룹에 join 하라는 초대메일을 받게 된다.  그리고 앱스토어에서 TestFlight 앱을 인스톨 하도록 안내 받게 된다.
TestFlight 앱은 beta app을 인스톨 할 수 있게 해 준다. UDID나 Provisioning Profiles 등을 track 하지 않아도 된다.


View the TestFlight App



Updates


beta app 이 인스톨 되면 TestFlight 은 새로운 build 가 생성될 때마다 테스터들에게 공지하게 된다. 그리고 어떤 부분에 포커스를 둘지 등을 제공받고 쉽게 feedback을 줄 수 있도록 한다.





Using TestFlight as a Beta Testers

Installing


테스터는 device 10개 까지 TestFlight 을 설치해서 사용 가능하고 여러가지 앱을 여러 개발자를 위해서 테스트 할 수 있다. 동시에 테스트 할 수 있는 앱의 갯수는 제한이 없다. TestFlight 은 iOS 8 이상의 버전이 깔려있는 iPhone, iPad 그리고 iPad touch 에서 iOS 앱을 테스트 하는데 사용할 수 있다. Mac 앱은 테스트 할 수 없다. 만약 beta app 이 테스터의 device 에 load 되지 않는다면 개발자에게 문의 한다.

Testing

invitation을 accept 하면 테스트를 위해 invite 된 앱의 beta version을 다운 받을 수 있다. 만약 live 버전이 있다면 beta 앱은 그 live version을 replace 할 것이다. beta 앱을 다운 받으면 앱 이름 옆에 오렌지색 점을 볼 수 있을 것이다. 이것은 beta 버전임을 알리기 위해 표시한 것이다. TestFlight 은 새로운 build 가 available 하면 notice를 보낼 것이다. 그리고 어느 부분에 Focus를 맞출지에 대한 정보를 제공할 것이다. TestFlight의 App Details 페이지에 있는 Provide Feedback 버튼을 클릭하면 쉽게 feedback을 보낼 수 있다. 이 이메일은 자동적으로 적절한 앱과 device detail등을 포함하게 되고 테스트는 추가사항과 screenshot 등을 덧붙이면 된다.

beta 테스트는 30일 동안 유효하고 시작은 테스터들에게 이 beta version 이 release 된 날이다. TestFlight 안에는 각 앱의 Open 버튼 안에 남은 일자가 표시돼 있다.

만약 beta App 에 In-App Purchase 기능이 포함되 있으면 그것을 구매하지 말아야 한다. 이 beta 버전에서는 금액이 결제되지 않을 것이다.

Opting Out (수신 거부)

email invitation 을 accept 하지 않으면 이 beta app은 설치되지 않을 것이다. 그리고 당신은 tester 리스트에 포함되지 않을 것이다. 또한 email 의 밑에 있는 링크를 눌러서 unsubscribe를 할 수 있다. 만약 그 invitation을 accept 했는데 더 이상 테스트 하고 싶지 않다면 TestFlight의 App Details 페이지에서 delete 할 수 있다.



저작자 표시 비영리 동일 조건 변경 허락
신고

'iOS' 카테고리의 다른 글

TestFlight Beta Testing  (0) 2015.09.24



공부하는 Introducing iOS8 의 Chapter 9 에 나오는 Selfie App 입니다.


우선 Main.storyboard를 이용해서 아래와 같은 화면을 만드세요.




가운데는 Image View 이고 왼쪽 오른쪽은 Bar Button Item 입니다.


import UIKit
import Social

class ViewController: UIViewController, UIImagePickerControllerDelegate, UINavigationControllerDelegate {


  @IBOutlet weak var myImageView: UIImageView!
 

  @IBAction func selfieTapped(sender: AnyObject) {
    var imagePicker = UIImagePickerController()
    imagePicker.delegate = self
   
    if UIImagePickerController.isSourceTypeAvailable(.Camera){
      imagePicker.sourceType = .Camera
     
      if(UIImagePickerController.isCameraDeviceAvailable(.Front)) {
        imagePicker.cameraDevice = .Front
      } else {
        imagePicker.cameraDevice = .Rear
      }
    } else {
      imagePicker.sourceType = .PhotoLibrary
    }
   
    self.presentViewController(imagePicker, animated: true, completion: nil)
  }
 
  func imagePickerController(picker: UIImagePickerController, didFinishPickingImage image: UIImage, editingInfo: [NSObject : AnyObject]?) {
    myImageView.image = image
    self.dismissViewControllerAnimated(true, completion: nil)
  }
 
  @IBAction func shareTapped(sender: AnyObject) {
    var social = SLComposeViewController(forServiceType: SLServiceTypeFacebook)
    social.addImage(myImageView.image)
   
    self.presentViewController(social, animated: true, completion: nil)
  }
}


우선 Facebook에 접속할 거니까 Social 을 import 합니다.

그리고 클래스 선언하는데에 UIImagePickerControllerDelegate, UINavigationControllerDelegate 를 추가합니다.


그리고 Take Selfie 와 Share button 들에 대한 함수를 만듭니다. Connection을 Outlet 이 아닌 Action으로 선택하면 됩니다.

각각 selfieTapped 와 shareTapped 라는 함수를 만듭니다.


그리고 가운데 사진이 들어갈 Image View에 대한 객체도 만들구요. 

여기서는 함수 이름을 imagePicker로 했습니다.



일단 selfieTapped 함수를 보면 UIImagePickerController() 에 대한 객체를 만들어서 delegate를 현재의 view로 설정합니다. (self)


그리고 if 문을 사용해서 Camera가 가능한지 여부를 체크하구요.

가능하면 또 다시 전면이 가능한지 체크를 합니다. 전면 카메라가 가능하지 않으면 후면 카메라를 지정하고 가능하면 전면 카메라를 지정합니다.


그리고 만약에 카메라 자체가 가능하지 않으면 전면 후면 확인할 필요 없이 그냥 Photo Library 를 지정합니다.


마지막 줄은 image Picker를 화면 전체에 표시하는데 밑에서부터 위로 올라오도록 설정한 겁니다.


그러면 Take Selfie 버튼을 눌렀을 때 카메라를 찍을 수 있는 화면이 나오는 설정을 한 겁니다. (카메라 기능이 없으면 Photo Library 가 나오구요.)


다음은 didFinishPickingImage delegate method 를 추가 합니다.


이 메소드는 사전에 Swift에 정의된 메소드 입니다. 이 메소드는 사용자가 사진을 찍었거나 Photo Library에서 사진을 선택 했을 때 호출 됩니다.

두번째 image 파라미터에 사진이 전달되게 되는 겁니다.


함수 내용을 보면 첫번째 줄에서 파라미터로 전달받은 image를 myImageView 의 image로 받습니다.

이렇게 받은 다음에 imagePicker가 없어지도록 합니다.


이러면 사진을 찍고 그 사진을 imagePicker에 받는 것까지 마친겁니다.


이제 이 사진을 맘대로 다룰 수가 있는데요.

이 앱에서는 Facebook으로 보낼 겁니다.


이 기능은 사용자가 Share 버튼을 누를 경우 일어나게 됩니다.

그러니까 shareTapped 함수 안에 코딩을 해야 되겠죠.


일단 서비스 타입을 Facebook으로 한 SLComposeViewController를 만듭니다. 그 변수 이름은 social 이구요.

그리고 그 controller 에 아까 받았던 이미지를 추가합니다.


마지막 줄은 SLComposeViewController 가 표시되도록 한 겁니다.






여기까지 진행이 되면 위와 같은 화면이 나오는데요.

이건 제 컴의 에뮬레이터로 실행한 겁니다. Facebook 이 setting 돼 있지 않아서 직접 Post 는 안되는데 아마 Setting을 하면 Posting 까지 될 겁니다.


저작자 표시 비영리 동일 조건 변경 허락
신고


Apple Document

https://developer.apple.com/library/prerelease/ios/documentation/NetworkingInternet/Reference/SLComposeViewController_Class/index.html

+ the Book (Introducing iOS 8 Swift programming from Idea to App Store by Steve Derico)


SLComposeViewController

SLComposeViewController 클래스는 SNS 를 지원하기 위한 view를 제공한다.
isAvailableForServiceType: 메소드는 트위터 같은 SNS 가 셋업 돼 있는지 view를 제공하기 전에 미리 체크하는 역할을 한다.

글을 올리는 것과 관련된 모든 메소드들은 boolean 값을 반환한다. 그 content 가 알맞지 않거나 view controller가 이미 사용자게게 그 내용을 present 한 경우에는 No를 반환한다. view controller에 제공하기 전에 반드시 그 content를 set 해야 한다. 사용자는 view controller 에 그 content가 제공된 이후에야 편집을 할 수 있다.

completionHandler property를 사용해서 handler를 사용해 사용자가 포스팅을 완료 했을 때 통보 받을 수 있다. 





project details 에서 Social.framework를 add 하고 view Controller 에서 import Social 을 해서 이 프레임워크를 import 한다.

SLComposeViewController는 생성될 때 반드시 serviceType 이 제공돼야 한다.
serviceType 프로퍼티는 다음과 같은 두개의 옵션이 있다.

SLServiceType Facebook
SLServiceTypeTwitter

어떤 서비스 타입이 사용 가능한지 체크하려면 isAvailableForServiceType 메소드를 사용한다.
if(SLComposeViewController.isAvailableForServiceType(SLServiceTypeFacebook)){}

아래와 같이 forServiceType 메소드를 사용해서 SLComposeViewController 를 생성할 수 있다.

if(SLComposeViewController.isAvailableForServiceType(SLServiceTypeFacebook)){
    var myComposeViewController = SLComposeViewController
    (for ServiceType: SLServiceTypeFacebook)
}

initial text를 세팅하려면 setInitialText 메소드를 사용한다.

var myComposeViewController = SLComposeViewController
(forServiceType: SLServiceTypeFacebook)

myComposeViewController.setInitialText("I love this app")

이미지를 추가하려면 addImage 메소드를 사용한다.

myComposeViewController.addImage(myImage)

메세지에 URL을 추가하려면 addURL 메소드를 사용한다.
이 메소드는 NSURL을 파라미터로 받는다. 이 NSURL은 string 이랑 아주 유사하다.

var myURL = NSURL(string: "http://www.google.com")
myComposeViewController.addURL(myURL)

이제 생성된 SLComposeViewController를 view Controller에 세팅을 하려면 ViewController(_:animated: completion:) 메소드를 사용한다.

self.presentViewController(myComposeViewController, animated: true, completion: nil)






Creating a Social Compose View Controller


저작자 표시 비영리 동일 조건 변경 허락
신고


요즘 도서관에서 이 책을 빌려서 Swift를 공부하고 있거든요.


Chapter 9 Camera, Photos, and Social Networks 를 공부하기 전에 애플의 document 를 미리 공부해 봤습니다. (UIImagePickerController)


중간에 이 책 9장에 있는 내용들도 좀 첨가 했어요.


https://developer.apple.com/library/ios/documentation/UIKit/Reference/UIImagePickerController_Class/


UIImagePicker Controller


해당 기기에서 제공하는 사진이나 비디오 촬영에 대한 기능을 다루는 클래스
그 외에 저장된 이미지나 비디오를 사용해 앱에서 활용할 수 있도록 해 줌
이 콘트롤러는 이 결과를 delegate object 에게 전달하게 된다.

초기화는 아래와 같이 한다.
var imagePicker = UIImagePickerController()

UIImagePickerControllerSourceTypeCamera: 사진이나 비디오를 찍을 때 사용해
UIImagePickerControllerSourceTypePhotoLibrary, UIImagePickerControllerSourceTypeSavedPhotosAlbum: 저장된 사진이나 비디오를 활용할 때 사용해

사용 방법
1. isSourceTypeAvailable를 사용해서 사용 가능 여부를 판별한다. UIImagePickerControllerSourceType enumeration 로부터 constant가 제공된다.


if UIImagePikcerController.isSourceTypeAvailable(.Camera) {
// 카메라 사용 가능 하면 소스타입을 세팅한다.
imagePicker.sourceType = .Camera
} else {
// 카메라 사용 불가능
}

기기에 따라 전면/후면 카메라가 있을 수 도 있는데 이럴 땐 이렇게 사용한다.

if UIImagePikcerController.isCameraDeviceAvailable(.Front) {
// 전면 카메라 사용 가능
} else {
// 전면 카메라 사용 불가능
}

if UIImagePikcerController.isCameraDeviceAvailable(.Rear) {
// 후면 카메라 사용 가능
} else {
// 후면 카메라 사용 불가능
}

사용 가능한 카메라가 없으면 UIImagePickerController는 사용자에게 Photo Library에서 사진이나 비디오를 고를 수 있도록 해 줄 수 있다.
imagePicker.sourceType = .PhotoLibrary

2. availableMediaTypesForSourceType 를 사용해서 가능한 소스타입을 체크한다. 사진과 비디오에 대한 사용을 구분해 준다.


3. mediaTypes property 를 세팅함으로서 image picker controller 에게 해당 미디어 타입(사진, 비디오)에 해당되는 UI를 조정해 준다.

모바일 타입을 바꾸려면 Mobile Core Services 프레임워크를 import 해야 한다.
이 프레임워크에는 다음과 같은 키워드가 있다.
kUTTypeImage : Photos and images
kUTTypeMovie : Movies and videos

mediaTypes 프로퍼티를 배열에 넣고 사용한다.
imagePicker.mediaTypes = [kUTTypeImage]
imagePicker.mediaTypes = [kUTTypeMovie]

4. 현재 활성화 된 View의 presentViewController:animated:completion:를 호출 함으로서 iPhone, iPod touch 등에 맞는 UI를 제공한다.
   새로운 view controller 로 현재 configure 된 image picker controller 를 passing 하게 된다.
   iPad 에서는 소스타입에 따라 image picker를 제공하는 방법이 다른데 아래를 참고 하면 된다.
   Camera               | Photo Library              | Saved Photos Album
   Use full screen     | Must use a popover     | Must use a popover

  
소스 타입이 UIImagePickerControllerSourceTypePhotoLibraryUIImagePickerControllerSourceTypeSavedPhotosAlbum이면 popover controller 를 사용해서 image picker를 제공해야 한다. full screen으로 제공하려고 하면 exception이 일어날 것이다.

Presenting and Dismissing the Popover.

UIImagePickerControllerSourceTypeCamera소스타입을 사용하면 이 image picer를 full-sccreen 이나 popover 아무거나 사용할 수 있다. 애플에서는 full-screen을 사용할 것을 추천하고 있다.

5. 새로 찍거나 저장돼 있는 사진이나 비디오를 선택하기 위해 사용자가 버튼을 누르거나 해당 작업을 cancel 하면 delegate object를 사용한 image picker 가 dismiss 하게 된다. 새로 찍힌 미디어는 delegate 가 이것을 기기의 카메라 롤에 저장할 수 있다. 이전에 저장된 미디어인 경우 delegate는 원하는 대로 이용 될 수 있다. 보다 자세한 사항은 Taking Pictures and Movies. 를 참조.

image picker controller를 customize 할 수 있다. 이렇게 하려면 overlay view를 사용한다. 이 overlay view 는 display 하려는 것을 콘트롤 하고   Capturing Still Images or Movies 에 있는 메소드들 을 사용하게 된다.

cameraOverlayView

custom overlay view를 display 할 수도 있다.
UIImagePickerController 클래스에 대한 Custom overlay view는 iOS 3.1 이상에서 가능하다. cameraOverlayView property 를 사용하면 된다.
Using UIImagePickerController to Select Pictures and Take Photos 에 그 예제가 있다.

Important
UIImagePickerController 는 portrait 모드만 지원한다. 이 클래스는 subclassing을 지원하지 않는다. view hierarchy 는 private 이고 modified 될 수 없다. 예외가 있다면 custom view를 cameraOverlayView 프로퍼티에 assign 할 수 있다. 그렇게 하면 추가적인 정보를 제공할 수 있고 카메라 인터페이스와 여러분의 코드 사이의 상호작용을 관리할 수 있다.




Delegate Object 제공하기

image picker controller를 사용하려면 UIImagePickerControllerDelegate protocol에서 허용된 delegate를 제공해야 한다. iOS 4.1 부터는 이미지와 함께 카메라 롤에 사진의 metadata 도 저장할 수 있게 됐다.
See UIImagePickerControllerDelegate Protocol Reference


UIImagePickerController에 미디어에서의 이벤트들을 전달하기 위해서는 delegate를 사용하는데 현재 뷰 콘트롤러에서 작업하는 경우는 self를 사용한다.
imagePicker.delegate = self
물론 클래스를 만들 때 이 delegate를 넣어야 한다.
class ViewController: UIViewController, UIImagePickerControllerDelegate {
}

UIImagePickerController는 UINavigationController를 상속했기 때문에 그 delegate도 UINavigationControllerDelegate 프로토콜을 상속하고 있다.
이 프로토콜은 push나 pops 같은 UINavigationController 이벤트의 update들을 전달한다. 이것을 사용하려면 이렇게 한다.
class ViewController: UIViewController, UIImagePickerControllerDelegate, UINavigationControllerDelegate {
}

사진이 찍히거나 앨범에서 사진이 선택 됐을 때 UIImagePickerControllerDelegate는 아래 메소드를 호출한다.
func imagePickerController(picker: UIImagePickerController!, didFinishPickingImage image: UIImage!, editingInfo: [NSObject : AnyObject]!) {}

사용자가 사진이나 비디오를 생성하거나 선택했을 때는 아래 메소드를 호출한다.
func imagePickerController(picker:UIImagePickerController, didFinishPickingMediaWithInfo: [NSObject : AnyObject]) {}

Flash Mode 조정하기

iOS 4.0 부터 사용자가 flash 모드, 전면/후면 카메라 사용 그리고 사진과 비디오 촬영을 선택할 수 있도록 하는 custom control을 제공할 수 있다. 그리고 프로그램으로 이 기능들을 컨트롤 할 수도 있다. 그리고 flash 의 strobe light 같은 것들도 콘트롤 할 수 있다.
cameraFlashMode property 를 UIImagePickerControllerCameraFlashModeOn UIImagePickerControllerCameraFlashModeOff에 세팅함으로서 flash LED를 켜거나 끌 수 있다.

Working with Movies


비디오 촬영시간의 디폴트 는 10 분이지만 videoMaximumDuration property를 사용해서 조정할 수 있다.
사용자가 share 버튼을 눌러서 MMS, MobileMe, YouTube, or another destination으로 비디오를 보낼 때 적당한 duration limit 과 적당한 video 퀄리티가 enforce 된다.

디폴트 카메라 인터페이스는 이전에 저장된 비디오를 editing 할 수 있도록 지원한다. Editing 은 비디오의 첫부분이나 끝 부분부터 일정 부분을 잘라내서 그 부분을 저장하는 기능이다. 이 인터페이스를 표시하려면 UIVideoEditorController 클래스를 사용한다.
See UIVideoEditorController Class Reference.

allowsEditing 프로퍼티를 true로 놓는다.
imagePicker.allowsEditing = true로
이렇게 하면 편집 스크린이 추가될 것이다.

Fully-Customized Media Capture and Browsing

fully-customized image/비디오 캡쳐를 실행하려면  Media Capture and Access to Camera에서 설명하고 있는 AV Foundation framework을 사용한다. 이 AV Foundation framework을 이용해서 카메라를 사용하는 것은 iOS 4.0 이후부터 가능해 졌다.

photo library를 살펴보기 위해 fully-customized image picker를 생성하려면 Photos framework에 있는 클래스들을 사용한다. 예를 들어 더 큰 thumbnail 이미지를 표시하는 custom image picker를 생성할 때 timestamp 와 위치정보를 포함한 이미지의 메타데이터를 사용하거나  MapKit 과 iCloud Photo sharing등과 같은 기능하고 같이 사용하도록 할 수 있다. 좀 더 자세한 사항은 Photos Framework Reference를 보면 된다. Photos framework을 이용한 Media browsing은 iOS 8.0 이상부터 가능하다.



Setting the Picker Source


저작자 표시 비영리 동일 조건 변경 허락
신고

[Swift] 현재 위치 맵에 표시하기

2015.09.14 09:28 | Posted by 솔웅


지난 글에 스위프트로 현재 위치 정보를 얻어서 다루는 방법에 대해 공부했습니다.

이번엔 현재 위치를 가지고 맵에 표시하는 방법을 공부해 보겠습니다.


오늘도 VEA Software의 강좌를 가지고 공부했습니다.


https://www.veasoftware.com/tutorials/2015/7/25/map-view-current-location-in-swift-xcode-7-ios-9-tutorial


이것은 xcode 7 으로 작업했더라구요. 그래서 소스를 받아서 6.4 에서 돌리니까 에러가 났습니다.

그래서 7.1 beta를 설치해서 거기서 돌리니까 제대로 돌아가더라구요.


그런데 이전에 작업했던 걸 불러오니까 자기가 Convert 시켰는데도 실행이 안되네요.

애플의 개발 툴도 아주 안정적이지는 않은 것 같아요.



하여간 일단 소스코드를 보겠습니다.


import UIKit
import MapKit
import CoreLocation

class ViewController: UIViewController, MKMapViewDelegate, CLLocationManagerDelegate
{
    @IBOutlet weak var mapView: MKMapView!
   
    let locationManager = CLLocationManager()
   
    override func viewDidLoad()
    {
        super.viewDidLoad()
       
        self.locationManager.delegate = self
        self.locationManager.desiredAccuracy = kCLLocationAccuracyBest
        self.locationManager.requestWhenInUseAuthorization()
        self.locationManager.startUpdatingLocation()
       
        self.mapView.showsUserLocation = true
       
    }

    override func didReceiveMemoryWarning()
    {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }

    // MARK: - Location Delegate Methods
   
    func locationManager(manager: CLLocationManager, didUpdateLocations locations: [CLLocation])
    {
        let location = locations.last
       
        let center = CLLocationCoordinate2D(latitude: location!.coordinate.latitude, longitude: location!.coordinate.longitude)
        let region = MKCoordinateRegion(center: center, span: MKCoordinateSpan(latitudeDelta: 1, longitudeDelta: 1))
       
        self.mapView.setRegion(region, animated: true)
       
        self.locationManager.stopUpdatingLocation()
    }
   
    func locationManager(manager: CLLocationManager, didFailWithError error: NSError)
    {
        print("Error: " + error.localizedDescription, terminator: "")
    }
   
}


CoreLocation과 관련된 것은 이전 글에서 다뤘으니까 여기서 따로 다루지는 않겠고...


맵을 사용하려면 우선 MapKit 을 import 하고 CLLocationManagerDelegate를 클래스에 추가합니다.


그리고 화면에 맵을 표시해야 하니까 Main.storyBoard 를 사용해서 MapView를 스크린에 얹고 변수 mapView 를 선언합니다.


다음에 viewDidLoad 메소드에 CLLocationManager()를 사용해 구현한 4개의 라인 밑에 맵뷰의 showsUserLocation을 true로 세팅합니다.


이러면 사용자 위치를 보여줄 수 있도록 사전 준비가 다 된 겁니다.


다음은 CLLocationManagerDelegate의 didUpdateLocations 메소드를 구현합니다.

이 메소드 안을 보면 우선 가장 최근의 위치정보를 location 에 담구요 


Core Location의 Data Type 중 하나인 CLLocationCoordinate2D를 사용합니다.

이 데이터 타입에는 CLLocationAccuracy, CLLocationDegrees, CLLocationDirection, CLLocationDistance 그리고 CLLocationSpeed 등이 있습니다.


CLLocationCoordinate2D는 위도와 경도 정보를 받는 겁니다.

이 위도 경도 정보를 center라는 변수에 담습니다.



다음은 MKCoordinateRegion 을 사용합니다. 이것은 MapKit의 데이터 타입중 하나입니다.

이외에 MKCoordinateSpan, MKMapPoint, MKMapSize, MKMapRect, MKZoomScale 등이 있습니다.


MKCoordinateRegion은 위도 경도에 해당하는 지역을 맵의 중앙에 위치하고 MKCoordinateSpan 은 지도의 scale을 정할 수 있습니다.


이렇게 region을 완료하면 그 다음에 이 region을 mapView 에 세팅을 하면 됩니다.

이때 animated는 true로 선언하구요.


그리고 나서 locationManager의 stopUpdatingLocation()을 호출해서 업데이트를 중지시킵니다.


이렇게 하면 지도에 현재의 위치를 표시하게 됩니다.





저작자 표시 비영리 동일 조건 변경 허락
신고

[Swift] 현재 위치 정보 다루기

2015.09.14 00:02 | Posted by 솔웅


요즘 Swift를 이용해서 iOS 모바일 어플리케이션 개발을 공부하고 있습니다.


스위프트로 현재 위치를 파악하려면 CoreLocation 을 사용해야 합니다.

아래 강좌를 한번 따라 해 봤는데요.


https://www.veasoftware.com/tutorials/2015/5/12/current-location-in-swift-xcode-63-ios-83-tutorial


일단 비쥬얼한 부분은 없이 코드만 있는 샘플입니다.

ViewController.swift 부분만 분석해 보겠습니다.


import UIKit
import CoreLocation

class ViewController: UIViewController, CLLocationManagerDelegate
{
   
    let locationManager = CLLocationManager()
   
    override func viewDidLoad()
    {
        super.viewDidLoad()
       
        self.locationManager.delegate = self
        self.locationManager.desiredAccuracy = kCLLocationAccuracyBest
        self.locationManager.requestWhenInUseAuthorization()
        self.locationManager.startUpdatingLocation()
       
    }
   
    override func didReceiveMemoryWarning()
    {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }
   
    func locationManager(manager: CLLocationManager!, didUpdateLocations locations: [AnyObject]!)
    {
       
        CLGeocoder().reverseGeocodeLocation(manager.location, completionHandler: {(placemarks, error)->Void in
           
            if (error != nil)
            {
                println("Error: " + error.localizedDescription)
                return
            }
           
            if placemarks.count > 0
            {
                let pm = placemarks[0] as! CLPlacemark
                self.displayLocationInfo(pm)
            }
            else
            {
                println("Error with the data.")
            }
        })
    }
   
    func displayLocationInfo(placemark: CLPlacemark)
    {
       
        self.locationManager.stopUpdatingLocation()
        println(placemark.locality)
        println(placemark.postalCode)
        println(placemark.administrativeArea)
        println(placemark.country)
       
    }
   
    func locationManager(manager: CLLocationManager!, didFailWithError error: NSError!)
    {
        println("Error: " + error.localizedDescription)
    }
}


우선 CoreLocation 을 import 합니다.

그리고   ViewController 에 Delegate 프로토콜을 불러옵니다.


이 ViewController라는 클래스는 UIViewController 클래스와 CLLocationManagerDelegate 프로토콜을 사용한다고 처음에 선언했는데요.

이 CLLocationManagerDelegate 프로토콜은 location과 heading updates를 CLLocationManager 로부터 받게 됩니다.

(Delegate는 제 생각에는 자바에서의 일종의 리스너 역할을 하는 것 같습니다.)

이 Delegate를 사용하는 것은 나중에 보게 되는데요. 사전에 정의된 수많은 location event들에 대해 필요한 메소드들을 불러서 구체적인 부분을 코딩해 나가시면 됩니다.

이건 나중에 보구요. 우선 순서대로 다시 보자면


CLLocationManager() 를 초기화 시킵니다. 이 클래스는 Location 과 heading 관련된 이벤트들을 전달하는 것을 configuring 하는 핵심 포인트인데요. 이 클래스의 인스턴스를 만들어서 location과 heading 이벤트를 언데 전달되고 이 이벤트들을 전달하는 일을 시작하고 끝내는 등의 역할을 하게 됩니다. 


위의 소스코드에서는 locationManager라는 이름으로 이 클래스를 초기화 시켰습니다.


그 다음은 viewDidLoad() 라는 함수를 보시면 됩니다.

이 함수는 UIViewController에 이미 정의돼 있는 함수인데요. UIViewController를 상속했기 때문에 이 함수를 Override 해서 사용할 수 있습니다.

이 함수는 해당 화면이 뜬 이후에 실행이 되게 됩니다.

그러니까 화면이 뜬 후에 제일 먼저 일어나야 할 일들을 여기에더가 정의 해 두면 됩니다.



super.viewDidLoad()로 이미 정의된 기능을 다 실행하도록 한 후에 아래 4개의 라인을 실행합니다.


        self.locationManager.delegate = self
        self.locationManager.desiredAccuracy = kCLLocationAccuracyBest
        self.locationManager.requestWhenInUseAuthorization()
        self.locationManager.startUpdatingLocation()


일단 CLLocationManager의 delegate를 self로 선언하고 다음에 desiredAccuracy는 Best 로 합니다.

이 외에 KCLLocationAccuracyNearestTenMeters, KCLLocationAccuracyHundredMeters, KCLLocationAccuracyKilometer, KCLLocationAccuraryThreeKilometer 등이 있습니다.

필요한 걸 골라서 쓰면 됩니다. Best 인 경우는 위치정보의 정확도가 가장 좋은 겁니다. 그러면 배터리 소모량이 많아 지겠죠.


그리고 requestWhenInUseAuthorization() 은 이 Location 정보를 이용하려고 할 때 사용자로부터 승인 여부를 묻는데 사용됩니다. 위치정보를 사용할 때 반드시 사용자의 허락을 받아야만 합니다. 이것 외에 requestAlwaysAuthorization() 도 있습니다. 첫번째 것은 앱이 foreground에서 실행 될 때에만 묻고 두번째 것은 forground이든 background 이던 다 물을 수 있습니다.




그 다음은 startUpdateingLocation()를 호출함으로서 Location Service를 사용할 수 있게 됩니다.


이제 locationManager는 사용자의 위치를 tracking 하고 그 값을 전달해 줄 수 있습니다.


didReceiveMemoryWarning()은 override 한 함수로 여기서 따로 살펴 보지는 않겠습니다.


그 다음에 나오는 함수가 바로 CLLocationManagerDelegate에 미리 정의 돼 있던 여러 메소드들을 사용하는 건데요.

첫번째로 didUpdateLocations를 가져왔습니다.

이 함수는 Location이 업데이트 됐을 때 실행되는 함수입니다.


그 안의 코딩을 보면 에러를 핸들링하고 에러가 없을 경우에는 위치 정보를 displayLocationInfo 함수에 전달해 주도록 하고 있습니다.


이 displayLocationInfo는 미리 정의돼 있던 함수가 아니라 개발자가 만든 함수입니다.


이 함수에는 전달받은 위치정보 중에서 locality (도시), postalCode(우편번호)administrativeArea(주) 그리고 country (나라) 정보를 콘솔에 print 하도록 했습니다.


그리고 마지막은 다시 CLLocationManager 의 Delegate에 미리 정의돼 있던 didFailWithError 메소드를 사용했습니다.

에러가 날 경우에는 에러 정보를 print 하도록 했습니다.


이렇게 해서 모든 소스코드를 분석해 봤습니다.



이 강좌에서는 위치 정보를 사용하기 위해서 info.plist에 NSLocationWhenInUseUsageDescription을 추가하라고 돼 있습니다.

그리고 제가 공부하던 다른 책에서는 NSLocationWhenInUsageDescription, NSLocationAlwaysUsageDescription 그리고 NSLocationUsageDescription을 추가하라고 돼 있구요.


그런데 저는 이 것들을 다 추가해도 앱이 제대로 실행이 안 되더라구요.

빌드는 제대로 되는데 저 위 그림에 있는 사용자에게 위치정보 사용 승인을 받는 alert 창이 안 뜨더라구요.


무슨 다른 세팅을 해야 되는지.... ? 잘 모르겠습니다.


일단 이 강좌에 있는 소스파일들을 다운 받아서 실행해서 테스트는 해 봤습니다.

다운 받은 소스의 info.plist에는 아무것도 추가가 안 돼 있던데...


왜 제가 만든 소스코드는 제대로 실행이 안되는지 모르겠네요.


이제 Current Location 정보를 받아서 사용하는 부분은 어느정도 알 것 같습니다.


저작자 표시 비영리 동일 조건 변경 허락
신고

Tutorial: How to use Auto Layout in Xcode 6

2015.08.27 05:22 | Posted by 솔웅


유튜브 강좌 따라 하다가 Constraint 부분에서 헤맸어.

몇번 잘 못 누르니까 컴터 속도가 막 느려지고 그러더라구.

맥북에어라서 사양이 낮아서 그런가...

좀 사양 높은 걸 사야되나?


하여간 Constraint 부분을 좀 확실하게 알려고 써핑하다가 아래 글 발견.

한번 따라해 봐야지.


원문은 http://www.brianjcoleman.com/autolayout-xcode6/





Tutorial: How to use Auto Layout in Xcode 6



애플은 새로 iPhone 6 (4.7in) 와 iPhone 6 Plus (5.5in)를 발표했다. 현재의 iPhone 4 (3.5in), iPhone 5 (4in), and iPad (9.4in) 이외의 또 다른 크기의 디바이스가 생긴 것이다. iOS 개발자로서 우리는 오랫동안 안드로이드와는 다르게 그렇게 다양하지 않은 화면 크기들을 대상으로 개발하는 잇점을 누려왔다. 이제 다양한 화면크기의 iOS 기기가 나왔다. 여러분의 앱은 이제 이 다양한 화면 크기에서 운용 될 수 있도록 해야 한다. 그렇지 않으면 애플은 당신의 앱을 reject 할 것이다. 그리고 사용자들은 그들의 기기에서 당신의 앱이 제대로 작동하지 않는다고 불평을 해 댈 것이다.


아래는 코드를 사용하지 않고 Storyboard를 사용해서 constraint를 사용해 view를 control 할 수 있는 tutorial을 제공하고 있다. 이 방법을 따르면 auto rotation 기능도 함께 적용할 수 있을 것이다.


Constraint를 사용해 Interface 디자인 하기


    1. Single View Application template 으로 새 프로젝트를 만듬. 프로젝트 이름을 AutoLayout 으로 함
    2.  interface를 편집하기 위해 Storyboard를 선택함. constraint의 장점 중 하나는 코딩을 하지 않고도 여러가지를 처리할 수 있다는 것이다. 많은 auto layout 적용이 이곳 Storyboard에서 처리 될 수 있다.
    3.  4개의 labeled button들을 추가한다. 라이브러리에서 round rect button을 view로 네번 드래그 하면 된다. 파란 가이드 라인이 각각의 버튼을 해당 코너에 배치하는 데 도움을 줄 것이다. 각 버튼을 더블 클릭해서 title을 할당한다.




    4.  Run 함. 현재 autorotation은 세팅됐는데 아직 autosize attribute들은 세팅하지 않았다. 빌드하고 run 해 봐라. Hardware Rotate left를 선택하라. 그러면 시뮬레이터가 아이폰을 landcape 모드로 바꿀 것이다. 어떤 버튼들은 스크린 밖에 위치해 보이지 않을 것이다. 우리는 이 부분을 바로 잡을 것이다.




    5.  아래 그림은 Auto Layout Menu의 예를 보여주고 있습니다. 스토리보드의 오른쪽 아래부분에 있습니다. 우선 작업할 view를 선택하시고 작업할 버튼을 선택하시면 됩니다.

Align – 정렬하는 constraint를 생성한다. 예를 들어 두개의 view를 왼쪽 정렬하는 경우.
Pin – spacing constraint를 생성한다. 예를 들어 UI constol의 너비를 정의하는 경우
Issues – layout 과 관련된 issue들을 해결할 경우
Resizing – resizing 관련 세팅을 할 경우



6. 이제 우리의 constrait들을 적용해 봅시다. 왼쪽 위에 있는 버튼을 선택하세요. 이 버튼의 constraint를 변경하기 위해 Pin 버튼을 선택하세요. top에 20px을 그리고 left에 0px을 넣으세요. “Add 2 Contraints” 버튼을 눌러서 해당 사항들을 적용합니다.



7. 이제 해당 버튼을 선택하면 파란 가이드라인을 보실 수 있을 겁니다. constraint가 적용돼 있다는 것을 말합니다. 아마 top left 버튼에 대해 아직 파란 선은 보실 수 없을 텐데요. 아직 해당 위치의 constraint들은 default이기 때문입니다.



8. 이제 같은 작업을 나머지 3개의 버튼들에도 수행합니다.




9. Run 합니다. 각각의 버튼들이 가까운 corner에 제대로 위치해 있을 겁니다. 화면 밖으로 나갔던 버튼들이 화면 안으로 제대로 들어왔습니다. 







Auto Layout에 대한 팁


origin, width 그리고 height등을 설정하지 않고 Auto Layout을 사용해서 view들을 세팅하면 language 나 locale 이 변경 됨에 따라 위치나 크기가 재조정 될 겁니다. Auto Layout은 모든 디바이스들에 대해 .storyboard와 .xib 파일 세트를 생성합니다.


설정된 width constraint 제거. - text 의 크기가 재조정 되도록 합니다. 만약 width constraint를 설정하시면 어떤 view에서는 해당 텍스트가 일정 부분 짤려서 나올 수도 있습니다.


intrinsic content size 사용 - text 필드와 레이블의 default 는 resize automatically 입니다. 만약 view가 텍스트에 맞게 조정되지 않았다면 해당 view를 선택하고 Editor > Size To Fit Content를 선택하세요.


leading and trailing attributes를 사용 - constraint를 적용할 때 leading and trailing for horizontal constraints를 사용하세요. 그러면 좌우를 equivalent 하게 해 줄 겁니다. leading and trailing attributes는 horizontal constraints의 디폴트 입니다.

인접한 view들에게는 Pin을 사용 - Pin을 하면 도미노 효과가 나타납니다. 한 view가 텍스트에 맞게 크기가 재조정되면 다른 view들도 똑같은 적용을 받는 겁니다. 그러지 않으면 어떤 디바이스들에서는 view들이 겹쳐지게 될 겁니다.


layout change를 항상 테스트하라 - iPhone 4, iPhone 5, iPhone 6, iPhone 6 Plus, and iPad 등 다양한 화면 사이즈에서 테스트 하세요.

윈도우의 minimize size나 maximum size를 세팅하지 마라 - 그냥 자동으로 재조정되도록 하는게 좋습니다.


Auto Layout은 새로운 프로젝트를 생성할 때 디폴트로 설정할 수 있습니다. 이전의 프로젝트에 Auto Layout을 적용하려면 첫번째 View Controller의 첫번째 view 를 선택하고 File Inspector를 선택합니다. 그리고 “Use Auto Layout”를 선택합니다.

저작자 표시 비영리 동일 조건 변경 허락
신고

swift Memo

2015.08.26 10:37 | Posted by 솔웅


* Set to whole width with some Margin


ctrl-Drag -> to right : Menu - Select Trailing space to container Margin : Orange Lines
  //      -> to left : Select leading space to the container margin
  //      -> to Top  : Select Top spacing to Top Layout Guide
==> will see blue line : completed for vertical
Orange - Click on Document outline (bottom left) -> Select lable 0
Yellow circle in View Controller section -> resolve the issue : Update Frame, Constraints, Reset to Suggested Constraints, Apply to all views in container -> select Update Frame -> Fix Misplacement -> Orange will go away


* iOS Simulator - Hardware - Rotate


* special Characters - Edit - Emoji & Symbols


* Array
- var xxx: Array<Double> = Array<Double>()
- var XXX = Array<Double>()
XXX.append(displayValue)


* right button on a element in Storyboard screen - disconnect to the methods


* fit elements (objects) to screen

Make perfect Grid for all elements in the screen. -> select 2nd icon :o: : Add New Constraints - top,left,right,bottom all 8
-> in View Controller Scene : Click on yellow icon on right top -> click on any yellow triangle - Apply to all views .... -> done : Test - rotate it



저작자 표시 비영리 동일 조건 변경 허락
신고

swift 함수 사용 예제

2015.08.25 13:46 | Posted by 솔웅



요즘 유튜브에서 Swift 관련 강좌 들으면서 공부하고 있거든.

따라 하다가 이해가 안 가서 보고 또 보고 했던 부분 정리해 두려고....

한참만에 이해 했네...


강좌는 Stanford - Developing iOS 8 Apps with Swift


import UIKit

class ViewController: UIViewController {
  @IBOutlet weak var nums: UILabel!
  var conditionA = false


  @IBAction func CalNums(sender: AnyObject) {
    let typed = sender.currentTitle!
    if conditionA {
      nums.text = nums.text! + typed!
    } else {
      nums.text = typed
      conditionA = true
    }
  }

  var operandStack = Array<Double>()


  @IBAction func enter() {
    conditionA = false
    operandStack.append(numsValue)
    println("operandStack = \(operandStack)")
  }
 
  var numsValue: Double{
    get {
      return NSNumberFormatter().numberFromString(nums.text!)!.doubleValue
    }
    set {
      nums.text = "\(newValue)"
      conditionA = false
    }
  }

  @IBAction func operator2(sender: UIButton) {
    let operation = sender.currentTitle!
    if conditionA {
      enter()
    }
    switch operation {
    case "✖️": performOperation(multiply)
    default: break
    }
  }
 
  func performOperation(operation: (Double,Double) -> Double) {
    if operandStack.count >= 2 {
      numsValue = operation(operandStack.removeLast(), operandStack.removeLast())
      println("numsValue is \(numsValue)")
      enter()
    }
  }
 
  func multiply(op1: Double, op2: Double) -> Double {
    return op1 * op2
  }


}


위데 색깔 들어가 있는 부분만 볼건데...

일단 빨간 부분...


파라미터가 operation: (Double,Double)->Double 이자나.

operation: 부분을 이해 못해서 한참 헤맸어.


일단 그 부분을 빼면은 더블형 두개를 파라미터로 받아서 더블형을 반환하는 함수인데...

performOperation 함수를 암만 봐도 return 이 없잖아.

그래서 이게 어떻게 된 건지 한참을 봤는데...


operation: (Double,Double)->Double 부분이 ( ) 로 감싸여져 있잖아.

이건 이 함수의 input 값과 return 값을 나타내는게 아니라 그냥 그 전체가 input parameter 라는 얘기지...

즉 더블형 두개를 받아서 더블형을 반환하는 operation 함수를 입력 파라미터로 받는 다는 얘기.


한참 헤맸네...


위에서 performOperation 를 호출 한 부분을 보면 

case "✖️": performOperation(multiply)

그 입력 값은 multiply가 되지.


그러면 performOperation 의 입력값은

multiply: (Double,Double)->Double 가 되는가봐.


즉 더블형 두개를 입력받고 더블형을 반환하는 multiply 라는 함수가 입력값이 되지.


이제 이 함수 선언 부분을 이해했으니까 그 안을 들여다 보자고.


그냥 다른 부분은 넘어가고 제일 중요한 부분이

numsValue = operation(operandStack.removeLast(), operandStack.removeLast())

여기서 operation 은 multiply 이니까 multiply 함수를 호출해서 반환 받은 값을 numsValue 변수에 넣어 주는거야.


입력값은 operandStack 배열의 마지막 값과 두번째 마지막 값.

뭐 다른 부분은 쉽게 이해가 가서 별로 정리해 둘 건 없고.


swift 에서 제공하는 함수 축약해서 사용하는 방법을 이 부분에서 설명이 되니 그거나 정리해야 겠다.




  func multiply(op1: Double, op2: Double) -> Double {
    return op1 * op2
  }


이 부분을 축약해서 case 문 안에 넣는 거야.


case "✖️": performOperation({ (op1: Double, op2: Double) -> Double in
      return op1 * op2 })


이것도 축약할 수 있는데.



multiply 함수가 더블형 파라미터 두개를 전달 받아서 더블형 을 반환 하는 것은 이미 함수에서 선언 했으니까 그 부분은 이렇게 생략해도 됨.


case "✖️": performOperation({ (op1, op2) in return op1 * op2 })


그리고 return 를 생략해도 되고..


case "✖️": performOperation({ (op1, op2) in op1 * op2 })


여기서 더 줄일 수 있는데..
multiply 함수에 두개의 더블형 파라미터가 전달 되는 것은 이미 알고 있으니까 그냥 아래 처럼 해도 된대.


case "✖️": performOperation({ $0 * $1 })


그리고 그냥 괄호도 없애 버리고 이렇게 해도 되고.


case "✖️": performOperation{ $0 * $1 }


swift는 이런 부분에서 굉장히  flexible 한 것 같애.


이게 원래 계산기 앱 소스코드인데.. 이렇게 축약하면 곱하기 나누기 더하기 빼기 모두 다 집어 넣어서 소스코드를 아래와 같이 간략하게 만들 수 있어.


import UIKit

class ViewController: UIViewController {
  @IBOutlet weak var nums: UILabel!
  var conditionA = false
 
  @IBAction func CalNums(sender: AnyObject) {
   
    let typed = sender.currentTitle!
   
    if conditionA {
      nums.text = nums.text! + typed!
    } else {
      nums.text = typed
      conditionA = true
    }
  }

  var operandStack = Array<Double>()
  @IBAction func enter() {
    conditionA = false
    operandStack.append(numsValue)
    println("operandStack = \(operandStack)")
  }
 
  var numsValue: Double{
    get {
      return NSNumberFormatter().numberFromString(nums.text!)!.doubleValue
    }
    set {
      nums.text = "\(newValue)"
      conditionA = false
    }
  }

  @IBAction func operator2(sender: UIButton) {
    let operation = sender.currentTitle!
    if conditionA {
      enter()
    }
    switch operation {
    case "✖️": performOperation{ $0 * $1 }
    case "➗": performOperation{ $0 / $1 }
    case "➕": performOperation{ $0 + $1 }
    case "➖": performOperation{ $0 - $1 }
    default: break
    }
  }
 
  func performOperation(operation: (Double,Double) -> Double) {
    if operandStack.count >= 2 {
      numsValue = operation(operandStack.removeLast(), operandStack.removeLast())
      println("numsValue is \(numsValue)")
      enter()
    }
  }
}




오늘 아주 좋은 걸 배웠어.. :)

그 강좌 계속 따라가면서 저 계산기 앱 마저 완성하면 swift도 많이 익숙해 질 것 같네....


저작자 표시 비영리 동일 조건 변경 허락
신고
이전 1 다음

티스토리 툴바