sonarqube – 코드 최적화하기

2분안에 설정하는 소나큐브

현재 진행중인 안드로이드 프로젝트를 개선하기 위해 소나큐브(http://www.sonarqube.org/)를 사용해보록 하겠습니다.

소나큐브는 프로젝트의 품질을 관리할 수 있도록 여러가지 모니터링 툴을 제공하는 오픈소스 플랫폼입니다. Java를 포함한 20가지가 넘는 프로그래밍 언어 (예: C#, C/C++, Javascript 등)로 제작된 프로젝트의 모니터링을 제공합니다.

참조

현재 환경은
OS : macOS sierra version 10.12.1
JAVA : 1.8


서버 다운로드 링크

https://sonarsource.bintray.com/Distribution/sonarqube/sonarqube-6.1.zip

스캐너 다운로드 링크

https://sonarsource.bintray.com/Distribution/sonar-scanner-cli/sonar-scanner-2.8.zip

예제 파일 링크

https://sonarsource.bintray.com/Distribution/sonar-scanner-cli/sonar-scanner-2.8.zip

위 파일을 다운로드 후 압축을 풀어준다.

소나큐브 서버 설치하기

$ mkdir ~/sonar
$ cd sonar
$ wget https://sonarsource.bintray.com/Distribution/sonarqube/sonarqube-6.1.zip
$ unzip sonarqube-6.1.zip
$ rm sonarqube-6.1.zip

소나큐브 스캐너 설치하기

$ cd ~/sonar
$ wget https://sonarsource.bintray.com/Distribution/sonar-scanner-cli/sonar-scanner-2.8.zip
$ unzip sonar-scanner-2.8.zip
$ rm sonar-scanner-2.8.zip

소나큐브 샘플 파일 설치하기

$ cd ~/sonar
$ wget https://github.com/SonarSource/sonar-examples/archive/master.zip
$ unzip master.zip
$ rm master.zip

환경변수 설정하기

$ emacs ~/.bashrc

아래 항목들을 파일에 추가해준다.

#sonar-qube
export PATH=/Users/username/sonar/sonarqube-6.1/bin/macosx-universal-64:$PATH
export PATH=/Users/username/sonar/sonar-scanner-2.8/bin:$PATH

소나큐브 서버 시작하기

$ sonar.sh console

소나큐브 프로젝트 스캔하기

프로젝트 위치에서 아래의 명령을 실행해주자.
!아래의 명령은 코드 분석을 시작하는 것이므로 프로젝트에는 이전에 프로젝트 설정파일이 포함되어 있어야 한다.

$ sonar-scanner

소나큐브 프로젝트 파일 생성하기

$ cat project/sonar-project.properties

위 파일안에 아래의 내용들을 추가해주자.

sonar.projectKey=my:project
# this is the name displayed in the SonarQube UI
sonar.projectName=Linkpay
sonar.projectVersion=1.0

# Path is relative to the sonar-project.properties file. Replace "\" by "/" on Windows.
# Since SonarQube 4.2, this property is optional if sonar.modules is set.
# If not set, SonarQube starts looking for source code from the directory containing
# the sonar-project.properties file.
sonar.sources=.
sonar.exclusions=**/*$$ViewBinder.java,**/*R.java

# Encoding of the source code. Default is default system encoding
#sonar.sourceEncoding=UTF-8

sonar.projectKey : 소나큐브 사이트 URL에 포함될 키
sonar.projectName : 소나큐브 사이트에서 보여질 프로젝트 이름
sonar.projectVersion : 소나큐브 사이트에서 보여질 프로젝트 버전
sonar.sources : 프로젝트 경로
sonar.exclusions : 분석 제외할 파일 패턴

끝.

Gralde – Unit test

Buil test configuration

app > build.gradle 환경 파일을 아래와 같이 수정한다.
instrumentTest.setRoot(‘tests’)라는 거.

android {
... 
  sourceSets {
        main {
            jniLibs.srcDirs = ['libs', 'src/main/libs']
            jni.srcDirs = []
        }
        instrumentTest.setRoot('tests')
        debug.setRoot('build-types/debug')
        release.setRoot('build-types/release')
    }
...
}

##Unit test example file

public class ExampleUnitTest {
...
    @Test
    public void addTest() throws Exception {
        assertEquals(4, 2 + 2);
    }
...
}

이상.

Emacs – Upgrade new emacs-live version.

기록하는 습관을 들이자.

emacs-live가 ~/.emacs.d/에 설치 되어있는지 확인하고, 만약 확인이 된다면 아래의 명령어를 입력해준다. 단 이때 git 저장소로부터 다운받아 설치가 되어 있어야 한다.

$ cd ~/.emacs.d/
$ git pull

이상.

Emacs – 프로젝트 생성

기존 프로젝트 의존성이 맞지 않아 오류가 발생된다.

새로 프로젝트를 생성한다면 아래의 설정대로 만들어주어야 한다.

기존 버전으로 사용할 경우 아래의 문제가 발생된다. midje 사용하고, lein repl을 사용했을 경우 cider쪽에서 some-> 함수를 찾지 못하는 문제가 발생한다.

오류를 줄이기 위한 가장 좋은 방법은 최신버전을 사용하는 것이다. (물론 최신버전에 또다른 오류가 발생될 수 있으나, 의존성 처리를 미리미리 해두는게 좋다.)

Global로 설정된 버전들 – cider-nrepl “0.9.1” – clojure “1.4.0”

최신 버전 – cider-nrepl “0.13.0” – clojure “1.8.0”

:dependencies [[cider/cider-nrepl "0.13.0"]]
:repl-options {:nrepl-middleware
                 [cider.nrepl.middleware.apropos/wrap-apropos
                  cider.nrepl.middleware.classpath/wrap-classpath
                  cider.nrepl.middleware.complete/wrap-complete
                  cider.nrepl.middleware.debug/wrap-debug
                  cider.nrepl.middleware.format/wrap-format
                  cider.nrepl.middleware.info/wrap-info
                  cider.nrepl.middleware.inspect/wrap-inspect
                  cider.nrepl.middleware.macroexpand/wrap-macroexpand
                  cider.nrepl.middleware.ns/wrap-ns
                  cider.nrepl.middleware.pprint/wrap-pprint
                  cider.nrepl.middleware.pprint/wrap-pprint-fn
                  cider.nrepl.middleware.refresh/wrap-refresh
                  cider.nrepl.middleware.resource/wrap-resource
                  cider.nrepl.middleware.stacktrace/wrap-stacktrace
                  cider.nrepl.middleware.test/wrap-test
                  cider.nrepl.middleware.trace/wrap-trace
                  cider.nrepl.middleware.out/wrap-out
                  cider.nrepl.middleware.undef/wrap-undef
                  cider.nrepl.middleware.version/wrap-version]}

위 내용을 정리하는 이유는 Midje와 cider 버전 차이가 맞지 않아 발생되는 문제로, lein과 사용되는 lein midje :autotest를 사용할 경우 아무 문제 없다. 하지만 문서상 lein midje ****보다는 lein repl에서 autotest명령을 수행함으로 써 하는 방식을 더 권장하고 있다.

사용해보니 왜 그렇게 권장하는지 알 수 있다.

$ lein repl
$ (use 'midje.repl)
$ (autotest) 

Google Apps Script – 파일 업로드하기

Google Forms은 파일 업로드를 지원하지 않습니다. 하지만 Google Apps Script와 HTML 웹 폼을 사용한다면, Google Drive에 파일을 업로드 할 수 있습니다.

예를 들어, 선생님이 학생들에게 레포트를 받기 위해 웹 폼을 작성하고, 작성 한 폼을 공유함으로써, 학생들은 그 웹폼에 접근하여 파일을 업로드 할 수 있습니다.

Google Script는 업로드하는 파일을 blob 타입으로 읽고 구글드라이브에 새로운 파일로 저장하게 됩니다. 파일이름, 확장자 컨텐츠 내용까지 다 지정할 수 있습니다.

Google에서 제공되는 Google Script를 사용해보도록 하겠습니다.

파일 구조는 두가지 파일로 (Code.gs, form.html)으로 구성됩니다. Code.gs – Google Apps Script입니다. 다양한 Google API를 사용할때 사용됩니다. form.html – 학생들에게 보이는 화면입니다. HTML,CSS, 그리고 JavaScript로 구성되어 있습니다.

아래와 같이 작성해주세요.

Code.gs

/* The script is deployed as a web app and renders the form */
function doGet(e) {
  return HtmlService.createHtmlOutputFromFile('form.html').setSandboxMode(HtmlService.SandboxMode.NATIVE);
  // This is important as file upload fail in IFRAME Sandbox mode.
}
 
/* This function will process the submitted form */
function uploadFiles(form) {
  
  try {
    
    /* Name of the Drive folder where the files should be saved */
    var dropbox = form.myName + " " + form.myEmail;
    var folder, folders = DriveApp.getFoldersByName(dropbox);
    
    /* Find the folder, create if the folder does not exist */
    if (folders.hasNext()) {
      folder = folders.next();
    } else {
      folder = DriveApp.createFolder(dropbox);
    }
    
    /* Get the file uploaded though the form as a blob */
    var blob = form.myFile;    
    var file = folder.createFile(blob);    
    
    /* Set the file description as the name of the uploader */
    file.setDescription("Uploaded by " + form.myName);
        
    /* Return the download URL of the file once its on Google Drive */
    return "File uploaded successfully " + file.getUrl();
    
  } catch (error) {
    
    /* If there's an error, show the error message */
    return error.toString();
  }
  
}

form.html

<!-- Include the Google CSS package -->
<link rel="stylesheet" href="https://ssl.gstatic.com/docs/script/css/add-ons.css">
 
<!-- You can also include your own CSS styles -->
<style>
  form { margin: 40px auto; }
  input { display:inline-block; margin: 20px; }
</style>
 
<script>
  // The function will be called after the form is submitted
  function doUploadFile() {
    document.getElementById('uploadFile').value = "Uploading File..";
    var f = document.getElementById('labnol');
    google.script.run.withSuccessHandler(fileUploaded).uploadFiles(f);
    return false;
  }
 
  // This function will be called after the Google Script has executed
  function fileUploaded(status) {
    document.getElementById('labnol').style.display = 'none';
    document.getElementById('output').innerHTML = status;
  }
  
</script>
 
<!-- This is the HTML form -->
<form id="labnol">
 
  <!-- Text input fields -->
  <input type="text" name="myName" placeholder="Your name..">
  <input type="email" name="myEmail" placeholder="Your email..">
 
  <!-- File input filed -->
  <input type="file" name="myFile">
 
  <!-- The submit button. It calls the server side function uploadfiles() on click -->
  <input type="submit" id="uploadFile" value="Upload File" 
         onclick="this.value='Uploading..';doUploadFile();">
 
</form>
 
<!-- Here the results of the form submission will be displayed -->
<div id="output"></div>

위 코드를 작성후 프로젝트 명을 지정해주세요. 이전에 지정되어도 상관없습니다. 프로젝트 명을 작성할 경우 지정된 이름이 drive> 아래 놓이게 됩니다.

프로젝트명은 ‘report’로 하겠습니다.

프로젝트가 생성되고, 위 파일을 성공적으로 작성하였다면, ‘Publish > Deploy as web app’을 선택해주세요.

Project version: new (새로 만들었다면, 기존것을 변경 할 수도 있습니다.) Execute the app as: Me (앱이 실행되기 위해 권한을 부여받기 위한 사용자가 되겠습니다. ) Who has access to the app: Anyone, even anonymous 누가 이 웹에 접속 할 수 있는지, 접근 권한을 선택 할 수 있습니다.

모든 설정을 완료하고 업데이트를 누르면, 공유 URL이 생성됩니다.

이상.

참조

이맥스 – 루비 제작자 “맷츠”, 어떻게 이맥스가 내 인생을 바꿧나?

원문

  1. 이맥스가 내 인생을 어떻게 바꿧나? “Yukihiro Matsumoto” – Matz @yukihiro_matz

  2. 1980

  3. 프로그래밍을 시작했다.

  4. ~

  5. BASIC

  6. 400 단계

  7. 1988

  8. 이맥스와의 만남

  9. Sun-3 위에서

  10. 200명 학부생들과 공유

  11. 이맥스를 시도했었다.

  12. 하지만 사용하지는 않았다.

  13. 이맥스는 금지 되어었다.

  14. 이맥스는 너무 많고 소중한 메모리가 소비하였다.

  15. 우리는 무료 소프트웨어를 받을 수 있는 자유가 있었다.

  16. 우리는 소스코드를 읽을 수 있는 자유가 있었다.

  17. 난 이맥스 소스코드를 다운받았다.

  18. 그리고 이를 연구하였다.

  19. 이맥스는 나의 첫번째 리스프 인터프리터였고,

  20. 나는 이맥스로부터 많은 언어에 대해서 배울 수 있었다.

  21. 포인터들 안에서 내장되어 있는 정수들 (?)

  22. 가비지 컬렉션을 청소했다.

  23. 리스프와 ‘C’ 사이에서의 대회로 불리었고

  24. 나는 리스프가 어떻게 동작하는지 이해할 수 있었다.

  25. 나는 리스프 오브텍트에 매료되었고

  26. 리스프 오브젝트는 C로부터 선언되었다. (?)

  27. 그리고 나는 Sparc Station을 얻었다. (SPARCstation(aka Sun-4) 시리즈는 1989년에 소개되었다.)

  28. 나는 이맥스를 사용하기 위해 다시 시작했고

  29. 이맥스는 나의 한부분이 되었다.

  30. 만약 이맥스에서 아무것도 좋아하지 않았다면, 나는 이것들을 바꿀수가 있었다.

  31. 이맥스는 완전하게 개조가 가능하였다.

  32. 이맥스는 프로그래머가 원하는 모든것을 바꿀 수 있다는걸 깨닫게 해주었으며,

  33. 이 모든것은 자유였다.

  34. 카바인딩 생각없이 모든 것을 바꿀 수 있었다. (?)

  35. 나는 이맥스 없이 아무것도 쓰고 싶지 않았다.

  36. 프로그램들, 문서 그리고 메일들까지

  37. 그래서 나는 내 전용 메일 클라이언트로 썼다.

  38. 이름하여 “email”

  39. 이맥스 리스프 안에서

  40. 이게 나의 첫번째 보잘거 없지 않은 리스프 프로그램이였다.

  41. 나는 매일 이것을 사용했다.

  42. 1993

  43. 나는 루비 개발을 시작했다.

  44. 이맥스 구현으로의 영향력은

  45. 태그 포인터들안에서 인티저는 코드였고,

  46. 이것은 간단한 영역과 가비지 컬렉션을 소비하여 사용하였다.

  47. 비슷한 오브젝트 모델에서 리스프로 사용했고 (여기서 리스프의 오브젝트의 “object”란 내부적으로 표현되 코드이고, OOP를 말하는 것이 아니다.)

  48. 그리고 나는 맨위에 OO 시스템과 같은 스몰토크를 넣었고

  49. 문법적으로 ALGOL/Ada/Eiffel들을 원했다.

  50. 하지만 이맥스 중독자로, 나는 언어 모드가 필요했었고,

  51. auto-indent는 필요한 것이었다.

  52. 1993년으로 돌아가, 문법이 표현된 언어를 위한 auto-indenting 언어 모드는 없었고

  53. 그래서 나는 ruby-mode.el를 만들었다.

  54. 이맥스 리스프와 정규식 표현을 다뤄야만 했고

  55. 매주 그렇게

  56. auto-indentation구현을 어떻게든 성공했다.

  57. 언어의 “end”를 위해

  58. 만약 진행하기 위한 ruby-mode를 만들지 않았다면,

  59. 루비의 문법은 바뀌었을지도 모른다.

  60. C와 같은 또다른 하나

  61. 다른 스크립트언어와 너무 비슷한

  62. 결과적으로 루비 현재의 인기를 차지하지 못햇을 것이다.

  63. 개요

  64. 1) 이맥스는 소프트웨어에 대한 자유를 가르쳐주었다.

  65. 2) 이맥스는 코드를 어떻게 읽는지 가르쳐주었다.

  66. 3) 이맥스는 리스프의 힘을 가르쳐 주었다.

  67. 4) 이맥스는 언어의 핵심이 어떻게 구현되는지 가르쳐 주었다.

  68. 5) 이맥스는 가비지 컬렉션이 어떻게 구현되는지 가르쳐 주었다.

  69. 6) 이맥스는 코드와 디버그를 도와주었다.

  70. 7) 이맥는 텍스트, 메일, 문서 작성과 편집을 도와주었다.

  71. 8) 이맥스는 효과적인 프로그래머가 될수 있도록 도와주었다.

  72. 9) 이맥스는 나를 해커로 만들어 주었다.

  73. 10) 이맥는 내 인생을 바꿔주었다.

  74. 영원히

  75. 감사합니다.

이맥스 – 텍스트 정렬하기

날씨 탓일까요? 뭔가 막혀있는 느낌이 자꾸 드네요. 이럴 땐 역시나 무엇인가에 몰두하는게 가장 좋더라고요.

이맥스 – 텍스트 정렬하기

이건 왜 몰랐을까? 아래와 같이 정렬되지 않은 텍스트를 일정한 규칙에 의해서 정렬할때 align-regexp기능을 사용할 수 있습니다.

rooney = 21
haha = 20
ray = 17

만약 문자 “=” 을 기준으로 정렬을 하고 싶다면, align-regexp을 치고 문자로 “=”을 입력해주세요.

결과는 아래와 같이 정렬된 것을 볼 수 있습니다.

rooney = 21
haha   = 20
ray    = 17

약간 고급스럽게 아래와 같이 사용 할 수 있습니다.

California 423,970 km²
Taiwan 36,008 km²
Japan 377,944 km²
Germany 357,021 km²
Iraq 438,317 km²
Iran 1,648,195 km²
Korea (North+South) 219,140 km²
Mexico 1,964,375 km²

위에 것을 아래와 같이

Taiwan                 36,008 km²
Korea (North+South)   219,140 km²
Japan                 377,944 km²
Germany               357,021 km²
California            423,970 km²
Iraq                  438,317 km²
Iran                1,648,195 km²
Mexico              1,964,375 km²

먼저 전체 텍스트를 영역 지정하고, CTRL+u 그리고 나서 align-regex명령을 입력합니다. 정규식 입력 란에

.* \([0-9,]+\).*

을 입력하고, 그룹에 대해서는

-1

, 공백은

1

을 입력합니다. 반복 실행은

n

을 입력해줍니다.

위와 동일한 효과를 가질 수 있는 두가지 명렁어가 더 있습니다.

  • sort-regexp-fields
  • sort-columns

급하게 잡힌 약속에 나가봐야해서 이만 쓰겠습니다.

Tool – 맥용 최강 터미널 툴 iTerm2!!!

iTerm2는 많은 기능들을 제공합니다.
터미널 사용자들은 미리 볼수 있고 해결한 수 있는 많은것들을 상상할 수 잇습니다. 그리고 지금 보는 것들은 아주 매력적인 것들입니다.

분활 화면

여러개화면을 각각 탭으로 나누는것과, 다른 세션을 한 화면에서 보여주는 기능을 제공합니다. 또한 세로든 가로든 화면을 나눌수 있고 패널에 번호를 매길수 있습니다.

NewImage

사용하지 않는 화면들은 딤처리 되어 현재 활동하고 있는 구간을 쉽게 확인 할 수 있습니다.

윈도우 핫키

단축키를 등록함으로써 iTerm2를 다른 어플리케이션 사이에서 화면 맨앞쪽으로 쉽게 불러올 수 있습니다. 또한 핫키를 통해서 아주 자주 사용하던 창을 선택 할 수 있습니다. 이 기능은 마우스로 손이 안가게끔 시간을 단축하게 해주죠.

NewImage

검색

iTerm2은 한페이지에서 검색할 수 있는 강력한 기능을 제공합니다. 화면에서 보이지는 않는 것까지 동일한것들을 찾아주고 하이라이트로 표시해줍니다. 또한 Regular Expression도 제공하지요.

NewImage

자동완성

간단하게 입력하고 필요할때

Cmd-;

을 입력하시면 자동 완성 창이 활성화 됩니다. 그리고 친적이 있고 이미 분석되어 리스트에 있는 항목들을 보여주죠.

NewImage

마우스 없이 복사하기

검색 명령어로 원하는 키워드를 검색하고, 탭 또는 시프트 탭을 활용하여 왼쪽 오른쪽 영역을 선택하세요. 그리고 원하는 영역이 지정되고 그 영역을 복사하고 싶을때는

Opt-Enter

를 눌러주세요.

NewImage

붙여 넣기 히스토리

붙여 넣기 히스토리는 재방문, 그러니까 최근에 사용했던 내용을 다시 사용하고 싶을 때 사용합니다. 목록에서 또한 선택이 가능하고 절대 읽어버릴일이 없을 겁니다.

NewImage

Instant Replay? 번역을 어떻게?

Instant replay 기능은 시간을 되돌릴수 있는 기능입니다.

NewImage

… 더 많은 내용은 아래의 링크로

http://iterm2.com/features.html

iOS – 음성 바꾸기

원문

필독
… 생략

iOS 기능 중 텍스트를 음성으로 내주는 기능있습니다. 정말 강력한 기능이고, 또한 남자 또는 여자 목소리 또한 선택이 가능합니다.

아래에 보시면 언어에 따른 각 다른 목소리를 골라 사용할 수 있습니다.

[AVSpeechSynthesisVoice 0x17e30940] Language: ar-SA, Name: Maged, Quality: Default, 
[AVSpeechSynthesisVoice 0x17d3e150] Language: cs-CZ, Name: Zuzana, Quality: Default, 
[AVSpeechSynthesisVoice 0x17e79700] Language: da-DK, Name: Sara, Quality: Default, 
[AVSpeechSynthesisVoice 0x17e50c50] Language: de-DE, Name: Anna, Quality: Default, 
[AVSpeechSynthesisVoice 0x17ec30f0] Language: el-GR, Name: Melina, Quality: Default, 
[AVSpeechSynthesisVoice 0x17e687f0] Language: en-AU, Name: Karen, Quality: Default, 
[AVSpeechSynthesisVoice 0x17e23be0] Language: en-GB, Name: Daniel, Quality: Default, 
[AVSpeechSynthesisVoice 0x17e6ffc0] Language: en-IE, Name: Moira, Quality: Default, 
[AVSpeechSynthesisVoice 0x17ec79b0] Language: en-US, Name: Samantha (Enhanced), Quality: Enhanced, 
[AVSpeechSynthesisVoice 0x17e795a0] Language: en-US, Name: Samantha, Quality: Default, 
[AVSpeechSynthesisVoice 0x17e75900] Language: en-ZA, Name: Tessa, Quality: Default, 
[AVSpeechSynthesisVoice 0x17e27ec0] Language: es-ES, Name: Monica, Quality: Default, 
[AVSpeechSynthesisVoice 0x17ec5e10] Language: es-MX, Name: Paulina, Quality: Default, 
[AVSpeechSynthesisVoice 0x17e799c0] Language: fi-FI, Name: Satu, Quality: Default, 
[AVSpeechSynthesisVoice 0x17ec61c0] Language: fr-CA, Name: Amelie, Quality: Default, 
[AVSpeechSynthesisVoice 0x17e75b10] Language: fr-FR, Name: Thomas, Quality: Default, 
[AVSpeechSynthesisVoice 0x17ee2460] Language: he-IL, Name: Carmit, Quality: Default, 
[AVSpeechSynthesisVoice 0x17ef5140] Language: hi-IN, Name: Lekha, Quality: Default, 
[AVSpeechSynthesisVoice 0x17e6f840] Language: hu-HU, Name: Mariska, Quality: Default, 
[AVSpeechSynthesisVoice 0x17e59bd0] Language: id-ID, Name: Damayanti, Quality: Default, 
[AVSpeechSynthesisVoice 0x17d2c950] Language: it-IT, Name: Alice, Quality: Default, 
[AVSpeechSynthesisVoice 0x17ebaec0] Language: ja-JP, Name: Kyoko, Quality: Default, 
[AVSpeechSynthesisVoice 0x17d42100] Language: ko-KR, Name: Yuna, Quality: Default, 
[AVSpeechSynthesisVoice 0x17ee3130] Language: nl-BE, Name: Ellen, Quality: Default, 
[AVSpeechSynthesisVoice 0x17d637d0] Language: nl-NL, Name: Xander, Quality: Default, 
[AVSpeechSynthesisVoice 0x17e7c8b0] Language: no-NO, Name: Nora, Quality: Default, 
[AVSpeechSynthesisVoice 0x17d3e430] Language: pl-PL, Name: Zosia, Quality: Default, 
[AVSpeechSynthesisVoice 0x17e33190] Language: pt-BR, Name: Luciana, Quality: Default, 
[AVSpeechSynthesisVoice 0x17eabf00] Language: pt-PT, Name: Joana, Quality: Default, 
[AVSpeechSynthesisVoice 0x17e2a650] Language: ro-RO, Name: Ioana, Quality: Default, 
[AVSpeechSynthesisVoice 0x17e232b0] Language: ru-RU, Name: Milena, Quality: Default, 
[AVSpeechSynthesisVoice 0x17ee6830] Language: sk-SK, Name: Laura, Quality: Default, 
[AVSpeechSynthesisVoice 0x17e64a10] Language: sv-SE, Name: Alva, Quality: Default, 
[AVSpeechSynthesisVoice 0x17e62fc0] Language: th-TH, Name: Kanya, Quality: Default, 
[AVSpeechSynthesisVoice 0x17df4080] Language: tr-TR, Name: Yelda, Quality: Default, 
[AVSpeechSynthesisVoice 0x17e76a10] Language: zh-CN, Name: Ting-Ting (Enhanced), Quality: Enhanced, 
[AVSpeechSynthesisVoice 0x17db4850] Language: zh-CN, Name: Ting-Ting, Quality: Default, 
[AVSpeechSynthesisVoice 0x17e2ecf0] Language: zh-HK, Name: Sin-Ji, Quality: Default, 
[AVSpeechSynthesisVoice 0x17e224c0] Language: zh-TW, Name: Mei-Jia, Quality: Default]

위 코드에 맞는 언어/나라

Arabic (Saudi Arabia) - ar-SA
Chinese (China) - zh-CN
Chinese (Hong Kong SAR China) - zh-HK
Chinese (Taiwan) - zh-TW
Czech (Czech Republic) - cs-CZ
Danish (Denmark) - da-DK
Dutch (Belgium) - nl-BE
Dutch (Netherlands) - nl-NL
English (Australia) - en-AU
English (Ireland) - en-IE
English (South Africa) - en-ZA
English (United Kingdom) - en-GB
English (United States) - en-US
Finnish (Finland) - fi-FI
French (Canada) - fr-CA
French (France) - fr-FR
German (Germany) - de-DE
Greek (Greece) - el-GR
Hindi (India) - hi-IN
Hungarian (Hungary) - hu-HU
Indonesian (Indonesia) - id-ID
Italian (Italy) - it-IT
Japanese (Japan) - ja-JP
Korean (South Korea) - ko-KR
Norwegian (Norway) - no-NO
Polish (Poland) - pl-PL
Portuguese (Brazil) - pt-BR
Portuguese (Portugal) - pt-PT
Romanian (Romania) - ro-RO
Russian (Russia) - ru-RU
Slovak (Slovakia) - sk-SK
Spanish (Mexico) - es-MX
Spanish (Spain) - es-ES
Swedish (Sweden) - sv-SE
Thai (Thailand) - th-TH
Turkish (Turkey) - tr-TR

실제로 사용 하는 방법을 알아보겠습니다.

let voice = AVSpeechSynthesisVoice(identifier: AVSpeechSynthesisVoiceIdentifierAlex)

다른 목소리를 사용하기 위해서, 이름으로 매칭하여 사용 할 수 있습니다. [code]identifier[/code]으로는 매치가 안됩니다.

목록 불러오기

var voiceToUse: AVSpeechSynthesisVoice?
for voice in AVSpeechSynthesisVoice.speechVoices() {
    if #available(iOS 9.0, *) {
        if voice.name == "Karen" {
        voiceToUse = voice
        }
    } 
} 

텍스트를 주어 음성을 내는 방법은 아래와 같습니다.

let utterance = AVSpeechUtterance(string: "Hello from iOS.")
utterance.voice = voiceToUse
let synth = AVSpeechSynthesizer()
synth.speakUtterance(utterance)