728x90

CentOS 6.10에서 APM(Apache + PHP + MariaDB) yum 설치한 환경에서 nodejs 환경 설정


먼저 https://link2me.tistory.com/1559 로 APM 설치과정이 필요하다면 참조한다.


npm install [모듈명] -g

모듈을 전역으로 설치할 때 사용하는 방식이다. g 는 global 을 의미한다.

일반적으로 특정 프로젝트가 아닌 전체 프로젝트에서 공통으로 사용할 수 있는 express-generator 나 nodemon 등을 전역으로 설치한다.


npm install [모듈명] --save

현재 작업중인 프로젝트에 모듈을 설치할 때 사용하는 방식이다.

--save 옵션을 지정하면 현재 프로젝트의 package.json 에 모듈 이름과 버전을 추가한다.


nodejs 는 자체적으로 Web Server 의 역할까지 함께 하므로 별도의 Web Server를 설치할 필요가 없다.


cd /usr/local/nodejs

npm install express-generator -g


이미지에서 보면 lib 디렉토리 하단에 모듈이 설치되는 걸 알 수 있다.


npm install nodemon -g



nodemon 을 설치하는 이유는 Web 서버의 디렉토리에서 npm start 로 nodejs를 실행하면 소스코드를 수정한 사항이 반영되지 않는다. nodemon 을 실행하면 소스코드를 수정할 때마다 서버를 재시작해야 하는 번거로움을 줄일 수 있다.


프로젝트 디렉토리 생성

cd /var/www/html/

express -e bestfood

를 해서 프로젝트 디렉토리를 생성한다.



package.json 에 추가된 모듈을 설치하기 위해 npm install 을 실행한다.

아래 이미지를 보면 node_modules 디렉토리가 추가된 것을 확인할 수 있다.



npm install formidable mysql --save

로 mysql 모듈을 설치한다. (MariaDB 와 내부적으로 95% 이상 동일)


npm  install body-parser


npm install serve-favicon


package.json 파일 내용을 열어보고 미 설치된 것이 있다면 npm install [모듈명] 으로 설치하면 된다.



사용포트 변경

nodejs 는 기본적으로 3000번 포트에서 동작하도록 되어 있다.

방화벽에서 3000번 포트를 open 해주거나 포트를 변경해야 정상 동작한다.

만약 iptime 공유기를 사용한다면, port forwarding 설정을 해줘야 한다.


간단하게 테스트를 위해서 webserver.js 파일을 만들어서 내용을 아래와 같이 적어준다.

IP 주소는 공유기 내부에서 사용하는 IP 주소를 적어준다.

const http = require('http');
// http 모듈에 들어있는 서버 기능을 사용하려면 require()메소드로 http모듈을 불러온다.

const hostname = '192.168.1.11'; // 실제 사용 IP로 변경해야 정상 동작됨
const port = process.env.PORT || 3000

// http 객체의 createServer() 메소드를 호출하면 서버 객체가 반환된다.
http.createServer((req, res) => {
  res.writeHead(200, { 'Content-Type': 'text/plain' });
  res.end('Welcome to Nodejs Server!!!\n');
}).listen(port, hostname, () => {
  console.log(`Server running at http://${hostname}:${port}/`);
});
// 이 서버 객체의 listen() 메소드를 호출하면 웹서버가 시작된다. 


node webserver.js

를 하면

와 같이 나온다.


Web 브라우저에서 동작되는지 테스트를 해본다.

http://ipaddress:3000/

ipaddress 는 public ip address 이다.

확인 방법은 http://www.findip.kr/ 으로 한다.


-------------------------------------------------------------------------------------------------------------

cd /var/www/html/bestfood/bin/

vi www

를 해서 보면


이제

npm start

를 하면 npm 을 이용하여 서버를 실행시킬 수 있다.


package.json 파일 내에 scripts 부분이 실행과 관련된 부분이다.


  "scripts": {
    "start": "node ./bin/www"
  },


  "scripts": {
    "start": "node ./bin/www" ,
    "test": "node ./app.js"
  },
로 수정한 다음에 npm test 를 실행시켜 보라.

npm start 로 실행해서 에러가 발생하면, www 파일 내에서 수정할 사항이 있다는 것이다.


설치된 패키지 확인
기존에 설치된 패키지를 확인할 때는 보통 package.json 파일을 열어 dependencies와 devDependencies 항목을 확인한다.
전체적인 의존성 트리를 확인하고 싶을 때는 npm ls 커맨드를 사용하면 된다.


블로그 이미지

Link2Me

,
728x90

필요한 걸 찾으려고 하니 어떤 게시글에 적혀 있는지 찾기 어려워서 별도로 적어둔다.


API28(Android 9) 이상을 사용하는 경우에는 추가로 고려할 사항이 있다.


AndroidManifest.xml 파일에 추가할 사항

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    package="com.link2me.android.MyPhone">

    <uses-permission android:name="android.permission.INTERNET" />
    <uses-permission android:name="android.permission.FOREGROUND_SERVICE" />

    <application
        android:allowBackup="false"
        android:icon="@drawable/icon"
        android:label="@string/app_name"
        android:supportsRtl="true"
        android:usesCleartextTraffic="true" 
<!-- http:// 통신일 경우에도 통신 가능하도록 -->

        android:theme="@style/AppTheme.NoActionBar">
        <activity android:name="com.link2me.android.MyPhone.Intro">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>

        <provider
            android:name="androidx.core.content.FileProvider"
            android:authorities="${applicationId}.fileprovider"
            android:exported="false"
            android:grantUriPermissions="true">
            <meta-data
                android:name="android.support.FILE_PROVIDER_PATHS"
                android:resource="@xml/provider_paths"
                tools:replace="android:resource" />
        </provider>
    </application>
</manifest>

Android 7.0(Nougat / API 24)에서 Intent로 URI 파일 경로 전송시 "file://" 노출되어 있으면 FileUriExposedException 오류가 발생하게 되고 앱이 종료된다.
앱간 파일을 공유하려면 "file://" 대신 "content://"로 URI를 보내야 한다.
URI로 데이터를 보내기 위해선 임시 액세스 권한을 부여해야 하고 FileProvider를 이용해야 한다.

그리고 res/xml/provider_paths.xml 생성을 해야 한다.

<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
    <external-path name="download" path="." />
</paths>




앱 build.gradle 은 androidX 로 변경한다.
오래된 코드를 Android Studio 에 맞게 수정하기 위해서는 이 코드 변환 과정이 필요하다.

dependencies {
    implementation fileTree(dir: 'libs', include: ['*.jar'])

    // implementation 'com.android.support:appcompat-v7:28.0.0'
    //implementation 'com.android.support.constraint:constraint-layout:1.1.3'

    implementation 'androidx.appcompat:appcompat:1.0.2'
    implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
    implementation 'gun0912.ted:tedpermission:2.0.0'
    implementation 'com.android.volley:volley:1.1.1'
}




블로그 이미지

Link2Me

,
728x90
cacti 는 업계 표준 오픈 소스 데이터 로깅 도구인 RRDtool 프론트 엔드용으로 설계된, 오픈 소스 웹 기반 네트워크 모니터링 및 그래프 도구이다.

SNMP를 통해 네트워크 스위치 또는 라우터 인터페이스를 폴링하여 네트워크 트래픽을 감시한다.
각자의 그래프 세트를 가진 복수의 사용자를 처리 할 수 있어서 전용 서버, 가상 개인 서버 및 코로케이션을 공급하는 웹 호스팅 제공 업체가 고객들의 대역폭 통계를 확인하기 위해 사용 가능하다.



Cacti를 설치하기에 앞서 Cacti를 사용하려면 설치하려는 서버의 APM(Apache, php, MySQL)이 설정 되어 있어야 사용할 수 있다. https://link2me.tistory.com/1559 에 yum 으로 설치하는 APM에 대한 스크립트가 있는데, 이 기반위에 설치하는 스크립트를 테스트한 걸 기록해 둔다.

최신버전(Cacti Server v.1.2.8)으로 설치를 해서인지 삽질을 엄청 많이 하면서 스크립트를 수정 보완했다.


RRDTool 최신 버전 및 cacti 최신버전 설치 스크립트 과정이다.


Cacti는 RRD에 특화된 정교한 프론트 엔드 툴이다.


SSH Shell 프로그램에서 접속한 # root mode에서 작성한 것이다.

복사 붙여넣기를 편하기 하기 위해서 편의상 #은 삭제했다. 간혹 #이 붙은 것은 주석처리 표시이다.


yum -y install openldap-devel pcre-devel lua-devel curl curl-devel libcurl-devel flex
yum -y install php-snmp php-gd php-devel
yum -y install gd gd-devel libart_lgpl libart_lgpl-devel zlib zlib-devel
yum -y install libxml2 libxml2-devel libpng libpng-devel
yum -y install freetype freetype-devel
yum -y install pango-devel
yum -y install php-ldap
yum -y install gmp php-gmp
yum -y install net-snmp-*


gmp 가 설치되지 않았다고 나오면,

PHP 7.3 을 yum 설치한 환경이라면

yum install -y --enablerepo=remi-php73 php-gmp

을 해줘야 된다.

기존에 설치된 것은 지워야 한다.

rpm -e --nodeps gmp.x86_64
yum -y erase rh-php70-php-gmp
즉 상황에 맞게 구글링해서 처리해야 하는데, 정보 검색이 잘못될 수 있고, 그러면 고생을 좀 할 수 있다.



# net-snmp 패키지를 설치하였다면 /etc/snmp/snmpd.conf 파일에서 4가지 설정사항을 수정해줘야 한다.
vi /etc/snmp/snmpd.conf
com2sec public default public
group public v1 public
group public v2c public
view all included .1
access public "" any noauth exact all none none

/etc/rc.d/init.d/snmpd stop
/etc/rc.d/init.d/snmpd start
# 또는
service snmpd restart


### RRDTOOL 설치 ####
RRD툴(RRDtool, round-robin database tool)은 시간에 따른 자료를 다룰 수 있는 도구이다. 그림 형식으로 시각화 해주는 기능도 있다.
MRTG를 모방해 일반화 하여 개발한 도구이며 자료 수집에 관한 일부분이 빠져 완전한 대체물은 아니지만, 네트워크 모니터링 분야에서 매우 인기있는 도구이다.
펄, 파이썬, 루비, Tcl, PHP를 지원한다.
라운드 로빈 데이터베이스(Round Robin Database, RRD)는 Tobias Oetiker에 의해 제작되었으며 현재는 전 세계의 수많은 사람들의 참여로 진행되고 있는 오픈 소스 기반의 소프트웨어이다.
Round Robin은 고정된 크기의 데이터와 현재 element에 대한 포인터로 동작하는 기술로 현재 데이터를 읽고 쓸 때 포인터는 다음 element로 이동하게 된다.
시작과 끝이 없는 원과 같이, Round Robin 기술을 사용하면 계속해서 데이터를 읽고 쓰는 작업이 가능하다.
사용하는 중에도 모든 가용 위치에 대한 사용이 가능하며, 자동적으로 이전의 위치에 대한 재사용이 가능하다.
이러한 방법으로 데이터베이스는 크기는 증가하지 않지만 어떠한 인위적인 작업 없이 사용 가능하게 된다.

#### RRDtool 설치: source 설치 방법

## 배포 사이트 : https://oss.oetiker.ch/rrdtool/ 에서 최신버전을 확인한다.
## cacti 에서 권장하는 버전을 설치하는 것이 좋을 것이다.
cd /root/rrdtool
wget https://oss.oetiker.ch/rrdtool/pub/rrdtool-1.4.9.tar.gz
tar xvfz rrdtool-1.4.9.tar.gz
cd rrdtool-1.4.9
./configure --prefix=/usr/local/rrdtool --disable-python --disable-tcl
make && make install
echo $?
여기서는 컴파일 작업 중 아무런 문제가 발생되지 않아 0 이 나타났다.
만약 0 이 아닌 다른 숫자가 나오면 제대로 설치가 안되었다는 것이더라.


### uninstall 하는 방법
# 처음 설치한 /usr/local/rrdtool 폴더를 찾아서 지운다.
cd /usr/local/
rm -rf rrdtool/
# 소스를 설치한 폴더로 이동하여 make uninstall 한다.
cd /root/rrdtool/rrdtool-1.7.2
./configure
make uninstall


#### cacti 설치하기 : cacti source 설치 방법
## https://www.cacti.net/download_cacti.php 에서 최신 버전을 확인한다.
# The latest stable version is 1.2.8, released 12/08/19.
# Cacti requires MySQL, PHP, RRDTool, net-snmp, and a webserver that supports PHP such as Apache.
# Requirements : RRDTool 1.4+ recommended, MySQL 5.x or greater, PHP 5.1 or greater

cd /usr/local/src
wget http://www.cacti.net/downloads/cacti-1.2.8.tar.gz
tar zxvf cacti-1.2.8.tar.gz
# mv cacti-1.2.8 cacti
cp -Rf cacti-1.2.8 /var/www/html/cacti

# cacti 디렉토리 권한 설정

cd /var/www/html/cacti
#chown cacti.cacti /var/www/html/cacti -R
chmod 755 /var/www/html/cacti


# 데이터 파일과 로그 파일이 저장되는 디렉토리 등 퍼미션을 777로 설정한다.
cd /var/www/html/cacti
chmod 777 rra log scripts
chmod 777 -R cache/
chmod 777 -R resource/
chmod 777 /var/lib/php/session


/usr/local/cacti/include/config.php 를 열어보면 아래처럼 설정되어있다.
$database_type     = 'mysql';
$database_default  = 'cacti';
$database_hostname = 'localhost';
$database_username = 'cactiuser';
$database_password = 'cactiuser';
$database_port     = '3306';
$database_retries  = 5;
$database_ssl      = false;
$database_ssl_key  = '';
$database_ssl_cert = '';
$database_ssl_ca   = '';

# 패스워드는 변경하는 것이 보안에 안전하다.

## cacti DB 생성 및 사용자 권한 등록
cd /var/www/html/cacti
mysql -u root -p
비밀번호 입력

show databases;
drop database cacti; -- db delete
create database cacti default character set utf8mb4 COLLATE utf8mb4_unicode_ci;
grant all on cacti.* to cactiuser@localhost identified by 'cactiuser'; -- 패스워드 반드시 변경한 걸 적어주시라.
GRANT ALL PRIVILEGES ON mysql.* TO cactiuser@localhost WITH GRANT OPTION;
flush privileges;


-- cacti 테이블 생성
show databases;
use cacti;
source cacti.sql
-- 육안으로 확인한다. 에러가 발생한 부분이 어떤 것인지 등등...
quit



====================================================
## cacti 테이블 생성
cd /usr/local/src/cacti
mysql cacti < ./cacti.sql -uroot -p
# 에러가 발생하면 이후 테이블 생성이 제대로 안되는 증상 발생하더라.
====================================================


# httpd.conf 찾기
find / -name httpd.conf
vi /etc/httpd/conf/httpd.conf

## php.ini 파일 찾기
find / -name php.ini
vi /etc/php.ini
memory_limit = 800M
max_execution_time = 60
date.timezone = Asia/Seoul
수정하고 저장한다.

#MariaDB 설정
## vi /etc/my.cnf 을 아래와 같이 수정한다.
vi /etc/my.cnf

[client]
default-character-set = utf8mb4

[mysql]
default-character-set = utf8mb4

[mysqld]
default-time-zone='+9:00'
character-set-client-handshake = FALSE
character-set-server = utf8mb4
collation-server = utf8mb4_unicode_ci

max_heap_table_size = 200M
max_allowed_packet = 64M
tmp_table_size = 64M
join_buffer_size = 128M
innodb_file_format = Barracuda
innodb_large_prefix = 1
innodb_buffer_pool_size = 1073741824
innodb_buffer_pool_instances = 10
innodb_flush_log_at_timeout = 3
innodb_read_io_threads = 32
innodb_write_io_threads = 16
innodb_io_capacity = 5000
innodb_io_capacity_max = 10000

저장(:wq) 하고 빠져나온다.

# cacti web 설정시 문제가 되면 SHOW GLOBAL VARIABLES LIKE 'innodb_buffer_pool_%' 로 확인하여 수정해야 한다.
# https://jsonobject.tistory.com/408 에 나온 내용을 참조하면 도움된다.


# MySQL 구동
service mysql start
service mysql stop
service mysql restart

#서비스 구동
service httpd start
service httpd stop
service httpd restart


## Crontab poller.php 등록
# vi /etc/cron.d/cacti 을 아래와 같이 설정한다
vi /etc/cron.d/cacti
*/5 * * * *    cacti   /usr/bin/php /var/www/html/cacti/poller.php > /dev/null 2>&1



### Web 으로 설치 ###
# http://서버IP/ cacti 로 접속하여 install버튼을 이용하여 설치를 마무리 한다.

## 기본 접속 세팅

RRDTool Binary Path : /usr/local/rrdtool/bin/rrdtool 로 수정해서 적어준다.


## User Login
admin / admin

## 패스워드 변경하라고 하면 패스워드를 변경한다.

# 반드시 대문자, 숫자, 특수문자를 포함해서 8자리 이상으로 변경해야 한다.



원하는 설정을 100% 충족해야만 다음으로 넘어간다.


service httpd restart 를 해주면 Web - No 가 사라진다.









## cacti 그래프 확인



# 서버에 가서 아래와 같은 명령어를 입력하면 그래프가 생성된다.

# whereis php 로 php 경로를 찾아 맞게 수정한다.
/usr/bin/php /var/www/html/cacti/poller.php –force


참고 : APM 소스 설치한 경우의 php 설치 경로


세부 설정 방법은 http://blog.syszone.co.kr/2551 하단에 있는 이미지를 참조하면 도움될 수 있다.

설치된 버전이 달라서 도움이 안될 수도 있다.

블로그 이미지

Link2Me

,
728x90

Cannot start session without errors, please check errors given in your PHP and/or webserver log file and configure your PHP installation properly.


에러가 접속되면서 phpMyAdmin 에 접속되지 않는다.


사용환경 : CentOS 6.10

APM 설치 : yum 설치


# chmod 777 /var/lib/php/session

를 하고 Web 브라우저로 phpMyAdmin 사이트를 다시 접속하면 문제가 해결되더라.





블로그 이미지

Link2Me

,
728x90

객체 지향 언어에서는 객체를 생성하기 위해서는 먼저 클래스를 선언하고, 해당 클래스로부터 객체를 생성한다.

하지만, 코틀린에서는 이런 과정을 거치지 않고도 객체를 생성할 수 있다.

object 키워드를 사용하면, 클래스가 아니라 객체 그 자체, 인스턴스가 된다.


코틀린에는 static keyword가 없고 object 키워드를 통해
- 싱글턴을 정의하는 방법
- 동반객체 companion object를 이용한 팩토리 메서드 구현
- 무명클래스(익명 클래스)의 선언
를 한다.


예제1

fun main(){
    // Person은 그 자체로 하나의 객체이기 때문에, 바로 .을 찍어 프로퍼티나 메서드에 접근할 수 있다.
    Person.name = "홍길동"
    Person.age = 30
    println("이름 : ${Person.name}, 나이 : ${Person.age}")
}

// object 는 subclass 의 명시적인 선언 없이 객체 생성
object Person {
    var name: String = ""
    var age: Int = 0
}
 


예제2

- object 키워드는 어떤 객체가 반드시 하나만 존재해야 할 때, 즉 싱글톤 패턴에 활용할 수 있다.

// 예제 2.1

fun main(args: Array<String>) {
    Singleton.printVarName()

    println("\nSingleton variableName Change")
    Singleton.variableName = "강감찬"
    var a = A()
}

object Singleton{
    init {
        println("Singleton class invoked.")
    }
    var variableName = "홍길동"
    fun printVarName(){
        println("변수명 : $variableName ")
    }
}

class A {
    init {
        println("Class init method. Singleton variableName property : ${Singleton.variableName}")
        Singleton.printVarName()
    }
}

// 예제 2.2
fun main(args: Array<String>) {
    var a = A()
    a.printVarName()

    println()
    Singleton.printVarName()
}

open class A {
    open fun printVarName() {
        println("I am in class printVarName")
    }

    init {
        println("I am in init of A")
    }
}

object Singleton : A() {
    init {
        println("Singleton class invoked.")
    }

    var variableName = "홍길동"
    override fun printVarName() {
        println(variableName)
    }
}



예제3. companion object

- 동반 객체(companion object)는 최상위 수준에서는 사용할 수 없고 클래스 내부에 정의하여 사용한다.

  동반 객체는 클래스 내부에 정의된 객체 선언이라고 할 수 있다.

  하나의 클래스에는 하나의 동반 객체만 포함될 수 있다.

- 동반 객체를 포함하는 클래스 내부에서는 동반 객체의 속성이나 함수를 자신의 속성이나 함수인 것처럼 인식하므로 동반 객체의 이름을 지정하지 않고 사용할 수 있다.

- 카 판매 버튼을 클릭할 때마다 카운트가 증가되는 함수라고 생각하면 된다.

- companion object 가 서로 다른 객체(아우디, 그랜저)의 카운트 총합을 자동 합산한다.

fun main(args: Array<String>){
    var car1 = CarSales("아우디")
    var car2 = CarSales("그랜저")

    car1.sales()
    car1.sales()
    car1.sales()
    car1.sales()

    car2.sales()
    car2.sales()

    println("${car1.name} : ${car1.count}")
    println("${car2.name} : ${car2.count}")
    println("총계 : ${CarSales.total}")
 
}

// object 는 subclass 의 명시적인 선언 없이 객체 생성

class CarSales(val name: String){
    // 코틀린에는 정적(static) 변수 혹은 메소드가 없고,
    // 대신 패키지 내에 함수를 선언하여 사용할 수 있다.
    companion object {
        var total = 0
    }

    var count = 0
    fun sales(){
        total++
        count++
    }
}


예제4

fun main(args: Array<String>){
    var first = MyHtml.generateHtmlObject("first")
    first.setColumnHeaders("1열","2열","3열")
    //println("first.generateTable() => ${first.generateTable()}")

    val second = MyHtml.generateHtmlObject("second", 5,5)
    second.setColumnHeaders("월","화","수","목","금")

    val third = MyHtml.generateHtmlObject("third",2,7)
    third.setColumnHeaders("적색","녹색","노랑","파랑","보라","검정","주황")

    println("생성된 table 개수 : ${MyRecord.showTableCount()}")
    for( (k,v) in MyRecord.showTable()) {
        println("\n <!-- $k table (${v.row} x ${v.col}) -->")
        println(v.generateTable())
        println()
    }
}

object MyRecord {
    private var _count = 0
    private val _tables = hashMapOf<String,MyHtml>()

    fun gen(table: MyHtml){
        _tables.put(table.name, table)
        _count++
    }
    fun showTableCount() = _count
    fun showTable(): Map<String,MyHtml> = _tables
}

class MyHtml {
    val name: String
    val row: Int
    val col: Int
    private val HEAD = "<table border='1' cell-spacing='10' cell-padding='10'"
    private val TAIL = "</table>"
    private lateinit var comment: String
    private val tableColumns = ArrayList<String>()

    private constructor(_name: String, row: Int, col: Int ){
        this.name = _name
        this.row = row
        this.col = col
    }

    fun setColumnHeaders(vararg colNames: String){
        this.tableColumns.addAll(colNames)
    }

    companion object _GenTable {
        fun generateHtmlObject(_name: String, row: Int = 2, col: Int = 3): MyHtml {
            val mh = MyHtml(_name, row, col)
            mh.comment = "<!-- auto-generator table by MyHtml v1.0 -->"
            // 테이블 객체 기록
            MyRecord.gen(mh)
            return mh
        }
    }

    private inner class Tr {
        val rowHtml = """
            |<tr>
            | ${"<td>-</td>".repeat(col)}
            |</tr>${"\n"}
        """.trimMargin()
    }

    private inner class Th(val wpx: Int = 40) {
        val headers = tableColumns.map {
            "<th width='$wpx'> $it </th>"
        }
        val rowHtml = """
            |<tr>
            | ${headers.joinToString("")}
            |</tr>
        """.trimMargin()
    }

    // 테이블 생성 실행
    fun generateTable() =
        """
                |$comment
                |$HEAD
                |${Th().rowHtml}
                |${Tr().rowHtml.repeat(row)}
                |$TAIL
            """.trimMargin()
}


블로그 이미지

Link2Me

,

net-snmp 5.4.4 설치

리눅스 2020. 1. 18. 02:08
728x90

SNMP(Simple Network Management Protocol) 은 원래 네트워크 장비를 관리하기 위한 통신 규약이다.
이제는 네트워크 장비뿐만아니라 컴퓨터, 전자장비까지 확장해서 사용하고 있다.

리눅스 시스템에서도 SNMP를 사용할 수 있다.


파일 다운로드

https://sourceforge.net/projects/net-snmp/files/net-snmp/5.4.4/

에서 파일을 다운로드 하여 파일을 서버에 업로드한다.

wget 으로 직접 받으니까 실행 에러가 발생해서 윈도우에서 받은 다음 서버로 업로드했다.


tar -xvzf net-snmp-5.4.4.tar.gz
cd net-snmp-5.4.4
./configure
엔터키 누르고 3번 누른다음 물음에 답을 하고 나서
make
make intall


혹시 잘못 되었으면 make distclean 을 해준다.


# snmpwalk  파일 생성여부 확인
cd /usr/local/bin/
ll



SNMP는 기본적으로 161번 포트를 사용한다.

그 중에 Trap 기능을 사용할 경우에는 162번 포트를 사용한다

방화벽 추가사항

-A INPUT -p udp --dport 161 -j ACCEPT
-A INPUT -p udp --dport 162 -j ACCEPT


snmp 서비스 실행

service snmpd start

동작 여부 확인

cd /usr/local/bin/
snmpwalk -v 2c -c public localhost system



블로그 이미지

Link2Me

,
728x90

코틀린에서는 접근자와 설정자를 따로 만들어줄 필요가 없다.
자바에서는 private 접근제한자로 은닉화된 멤버 변수에 getter/setter 메소드를 사용해서 접근한다.
코틀린은 property가 getter/setter를 대체한다.

코틀린에서 속성(property)란
최상위 변수(함수나 클래스 외부에 정의된 변수)나 클래스의 멤버 변수로 선언하면 속성으로 간주된다.
클래스의 멤버 변수는 모두 private 제한자로 지정된다.
따라서 해당 클래스의 내부의 getter와 setter를 통해서만 속성을 참조할 수 있다.

 

package com.myapp.funcargs

fun main(){
    val a = Person("홍길동", 30)
    println(a)
    //println(a.toString())

    val b = a.copy("이순신")
    println(b)

    val c = b.copy(age=40)
    println(c)

    val(name, age) = Person("강감찬",35)
    println("성명 : $name, 나이 : $age")



    val obj = Pair<String, Int>("김좌진", 50)
    println(obj)
}

// 데이터는 보유하지만 아무것도 안하는 클래스
data class Person(val name: String, val age: Int)
// 파라미터 없는 기본 생성자가 필요한 경우에는
// data class Person(val name: String = "", val age: Int = 0)
// 모든 프로퍼티에 기본 값을 설정해 주면 된다.
// 기본 생성자에서 선언된 속성을 통해, 컴파일러가 자동으로 toString(), hashCode(), equals() 등을 생성한다.
// 명시적으로 정의해준 경우에는 컴파일러가 자동으로 생성하지 않는다.

 

실행결과

 

 

import android.os.Parcelable
import kotlinx.android.parcel.Parcelize
 
@Parcelize
data class Memo_AddEdit (
    var idx: String,
    var memo: String,
    var userID: String,
    var userNM: String,
): Parcelable
 
 
class MainActivity : AppCompatActivity() {
    private lateinit var mContext: Context
    private lateinit var mMemo_AddEdit: Memo_AddEdit
 
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        mContext = this@MainActivity
 
        initView()
    }
 
    private fun initView() {
        // 값을 할당함으로써 초기화가 된다.
       mMemo_AddEdit = Memo_AddEdit("0","",userid,userNM)
 
    }
}

 

'안드로이드 > Kotlin 문법' 카테고리의 다른 글

코틀린 null 안전과 예외  (0) 2020.05.05
코틀린 object  (0) 2020.01.19
코틀린 고차함수와 람다 그리고 확장함수  (0) 2020.01.14
코틀린 접근 제한자  (0) 2020.01.14
코틀린 패키지  (0) 2020.01.13
블로그 이미지

Link2Me

,

macOS 카탈리나

iOS/MACBOOK 2020. 1. 16. 13:42
728x90

맥OS 10.15 카탈리나는 100% 64bit 기반 운영체제다. 애플은 이전 버전인 맥OS ‘모하비(Mojave)’가 32bit를 지원하는 마지막 맥OS가 될 것이며, 카탈리나부터는 더이상 32bit 앱을 사용할 수 없다고 강조해왔다. 지난 4월 맥OS 업데이트에서는 32bit 앱 실행 시 업데이트 경고 창을 띄우는 기능을 추가하면서 32bit 지원 종료를 꾸준히 예고해왔다.

하지만 애플의 경고에도 불구하고 적지 않은 사용자들이 구형 프로그램을 계속 사용하고 있으며, 그로 인해 이번 카탈리나 업데이트 이후 앱 실행 불가 문제가 더욱 크게 불거지고 있다고 더 버지 등 외신들은 지적했다.

실행 불가 문제는 어도비의 ‘포토샵(Photoshop)’이나 ‘라이트룸(Lightroom)’같이 주로 사진과 영상 편집, 음악 작곡 및 편집 등 고가의 전문가용 애플리케이션에서 주로 발생하는 것으로 나타났다. 업그레이드 비용이 너무 비싸거나, 정기적으로 사용료를 내는 구독형 서비스가 부담스러운 사용자들이 추가 과금 없이 영구적으로 사용할 수 있는 구버전 애플리케이션을 사용해 왔는데, 카탈리나 업데이트로 피해를 보고 있다는 것.


블로그 이미지

Link2Me

,
728x90

모니터 연결 케이블

DVI 케이블
- 싱글링크 지원 최대 해상도 : 1920 X 1200 @60Hz
- 듀얼링크 지원 최대 해상도 : 2560 X 1600 @60Hz

HDMI 케이블
- HDMI 1.4 지원 최대 해상도 : 3840 X 2160
- HDMI 2.0 지원 최대 해상도 : 3840 X 2160 @60Hz

Display Port
- DP 1.2 지원 최대 해상도 : 3840 X 2160 @75Hz
- DP 1.3 지원 최대 해상도 : 3840 X 2160 @120Hz
- DP 1.4 지원 최대 해상도 : 3840 X 2160 @240Hz


20번 핀이 살아 있는 산업용 케이블은 가정용에서는 필요없다.
잘못하면 모니터가 사망하거나 VGA 카드에 치명상을 입히기도 한다.
포트에는 버전이 존재하지만, 케이블에는 버전은 존재하지 않는다.


20번이 아예 동작 안하는 케이블로 구입하는 것이 정신 건강에 좋다고 유투브에 나온다.


블로그 이미지

Link2Me

,
728x90
코틀린 함수의 기본형태
fun 함수명(매개변수):Unit {
}

fun 함수명(매개변수):리턴타입 {
   return 값
}


고차함수

고차함수(High-order Function)란 다른 함수를 인자로 사용하거나, 함수를 결과값으로 반환하는 함수를 말한다.


package com.myapp.funcargs

fun main(){
    val a = sum(4,5) // 일반 인자
    println("a result : $a")
    val b = mul(sum(1,2), 3) // 인자에 함수 사용
    println("b result : $b")

    println("ResultFun : ${resultFun()}")
}

fun sum(a: Int, b: Int) = a + b
fun mul(a: Int, b: Int) = a * b
fun resultFun(): Int {
    return mul(3,5) // 함수의 반환 값으로 함수 사용
}


람다 표현식

람다식, 또는 람다 함수는 프로그래밍 언어에서 사용되는 개념으로 익명 함수 (Anonymous Functions)를 지칭하는 용어이다.


val lambdaName: Type = {argument -> codeBody}


람다 함수는 { } 안에 매개변수와 함수 내용을 선언하는 함수로 다음 규칙에 따라 정의한다.
- 람다 함수는 항상 { }으로 감싸서 표현해야 한다.
- { } 안에 -> 표시가 있으며 -> 왼쪽은 매개변수, 오른쪽은 함수 내용이다.
- 매개변수 타입을 선언해야 하며, 추론할 수 있을 때는 생략할 수 있다.
- 함수의 반환값은 함수 내용의 마지막 표현식이다.


fun sum(a: Int, b: Int) = a + b
를 람다 함수로 정의하면
val sum ={a: Int, b: Int -> a + b}

또는

val sum: (Int, Int) -> Int ={a, b -> a + b}


package com.myapp.funcargs

fun main(){
    val a = sum(4,5) // 일반 인자
    println("a result : $a")
    val b = mul(sum(1,2), 3) // 인자에 함수 사용
    println("b result : $b")

    println("ResultFun : ${resultFun()}")

    val c:(String)->Unit ={str -> println("$str 람다함수")}
    b(c)
}

val sum ={a: Int, b: Int -> a + b}
// val sum: (Int, Int) -> Int ={a, b -> a + b}
// val mul ={a: Int, b: Int -> a * b}
val mul: (Int, Int) -> Int ={a, b -> a * b}
fun resultFun(): Int {
    return mul(3,5) // 함수의 반환 값으로 함수 사용
}
fun b (function: (String)->Unit){
    function("b가 호출한")
}




확장함수(Extension Function)
Extension functions(확장 함수)는 기존에 정의된 클래스에 함수를 추가하는 기능이다.
자신이 만든 클래스는 새로운 함수가 필요할 때 쉽게 추가할 수 있다.
하지만 Standard Library 또는 다른 사람이 만든 라이브러리를 사용할 때 함수를 추가하기가 매우 어렵다.

확장 함수는 fun 클래스이름.함수이름(매개변수): 리턴타입 { 구현부 }으로 정의할 수 있다.

또는
fun 확장하려는대상.함수명(매개변수):Unit {
}

fun 확장하려는대상.함수명(매개변수):리턴타입 {
   return 값
}


확장함수 예제1

class Car {
    fun getPrice() : Int {
        return 8000
    }
}

fun Car.getBrandName() : String {
    return "BMW"
}

fun Car.getBrandName2() : Car {
    println("KIA")
    return this
}

fun main(args: Array<String>) {
    val car = Car()
    println(car.getBrandName())
    println(car.getBrandName2().getPrice())


확장함수 예제2

fun String.getLonggerLength(x: Int) : Int {
    return if(this.length > x) this.length else x
}

fun main(args: Array<String>) {
    println("Hello".getLonggerLength(3))
} 

fun main(args: Array<String>) {
    println("Hello".getLonggerStringLength("Have a nice day!"))
}

fun String.getLonggerStringLength(x: String) : Int {
    return if(this.length > x.length) this.length else x.length
}


확장함수 예제3

class Car {
    fun getPrice(): Int {
        return 10000
    }
}

fun Car.getPrice(): Int {
    return 20000
}

fun Car.getPrice(price: Int): Int {
    return 30000
}

fun main(args: Array<String>) {
    val car = Car()
    println(car.getPrice())
    println(car.getPrice(0))


확장함수 예제4

fun List<Int>.getHigherThan(num: Int): List<Int> {
    val result = arrayListOf<Int>()
    for (item in this) {
        if (item > num) {
            result.add(item)
        }
    }
    return result
}

fun main() {
    val numbers: List<Int> = listOf(1, 2, 3, 4, 5, 6, 7)
    val filtered = numbers.getHigherThan(3).toString()
    System.out.println(filtered)
}
 


'안드로이드 > Kotlin 문법' 카테고리의 다른 글

코틀린 object  (0) 2020.01.19
코틀린 data class (자바의 getter 와 setter 클래스)  (0) 2020.01.16
코틀린 접근 제한자  (0) 2020.01.14
코틀린 패키지  (0) 2020.01.13
코틀린 인터페이스  (0) 2020.01.13
블로그 이미지

Link2Me

,
728x90

접근 제한자란 객체가 공개되어야 하는 범위를 정해주는 역할을 한다.

자바에서는 접근 제한자(Access Modifier)라는 용어를 사용하고
코틀린에서는 Visibility Modifier로 사용하는데, 우리말로는 접근 제한자 또는 가시성 제한자라고 할 수 있다.
코틀린에서 접근 제한자를 가질 수 있는 요소로는 class, object, interface, constructor, function, property 등이 있다.

자바에서는 접근 제한자를 붙이지 않으면 default(package-private) 이다.
그러나 코틀린에서는 아무것도 붙이지 않으면 public 이다.

코틀린에서 말하는 모듈은 자바와는 약간의 차이가 있는데, 자바에서의 모듈은 기능이 비슷한 클래스들의 집합체를, 코틀린에서는 동일한 컴파일의 집단을 의미한다.


패키지 레벨의 접근제한자

프로퍼티와 함수를 최상위(Top) 레벨에 작성한다는 것은 클래스에 멤버로 포함하지 않고 코틀린 파일에 정의하는 것을 의미한다.
package foo

public val myData: Int = 10
public fun myFun() {}
public class myClass() {}

- 접근 제한자를 표기하지 않으면 public이 기본으로 설정되며, 누구나 접근이 가능하다.

- private : 해당 .kt 파일 내부에서만 사용 가능하다.
- internal : 프로젝트의 모듈 안에서 누구나 접근이 가능하다.
- protected : 최상위(top-level)에서는 사용할 수 없다.
 

클래스와 인터페이스의 접근제한자
클래스 또는 인터페이스 안에 선언되는 멤버들에 사용되는 접근 제한자는 다음과 같은 의미를 갖는다.
- public : 누구나 접근이 가능하다.
- private : 클래스 내부에서만 접근이 가능하다.
- protected : 클래스 내부와 상속받는 객체에서 접근이 가능하다.
- internal : 프로젝트의 모듈 안의 누구나 접근이 가능하다.


private, protected, public 과 Java와 코틀린에서 같은 의미로 사용된다.
하지만 internal은
자바에서는 default(같은 패키지내에서만 접근가능)
코틀린에서는 같은 모듈안에서만 사용 가능하다. 


생성자의 접근제한자
생성자에도 접근제한자를 붙일 수 있다. 기본은 public 생성자로 누구나 접근이 가능하다.
internal을 붙이면 모듈 내에서만 접근 가능하다.
private을 붙이면 클래스 내에서만 접근이 가능하여 외부에서 생성할 수 없다.

// private 생성자
class Person private constructor(a: Int) {
}



Java 접근 제한자

접근 제한자는 Class 의 멤버에 대해 다른 Class 에서 접근하는 것을 제한하는 용도로 사용된다.

- public : 모든 Class 에서 접근 가능

- protected : 같은 패키지에 있는 Class, 그리고 다른 패키지의 자손 클래스에서 접근이 가능

- default : 같은 패키지에 있는 Class 들만 접근 가능

  String name; // 아무런 접근 제한자도 지정되지 않았으므로 default 접근 제한자다.

- private : 같은 Class 내에서만 접근 가능


지시자

클래스 내부

동일 패키지

상속받은 클래스

이외의 영역

 private


 X

X

X

 default


X

X

 protected


X

 public




블로그 이미지

Link2Me

,
728x90

코틀린에서 프로젝트(Project)는 모듈(Module), 패키지(Package), 파일(File)로 구성되어 있다.
프로젝트에는 모듈이 있고 모듈은 다시 패키지로 구성되어 있다.


Java는 파일명과 클래스명이 동일해야 하지만, 코틀린은 public 클래스는 하나만 사용 해야하는 규칙이 없다.


코틀린 파일은 .kt 확장자를 가지며 맨 위에는 이 파일이 어떤 패키지에 포함된 것인지 코틀린 컴파일러가 알 수 있도록 패키지 이름을 선언해야 한다.
만약 패키지 이름을 선언하지 않으면 그 파일은 자동으로 default 패키지에 포함된다.
파일이 패키지 안에 들어있어도 패키지 이름을 선언하지 않으면 default 패키지에 포함된 것으로 인식한다.
파일에 클래스가 여러 개 정의되어 있다면 파일은 단순히 클래스를 묶는 역할을 하고 kt 확장자가 붙게 된다.
코틀린에서는 파일명과 클래스의 선언 개수에 큰 의미를 두지는 않는다.
같은 파일에 있는 여러 개의 클래스는 모두 그 파일에서 지정한 패키지로 인식한다.


패키지 이름은 파일 맨 위에 적는다. 이때 패키지 이름 앞에 package라는 키워드를 함께 입력해야 패키지 이름으로 인식한다. 단, 패키지의 이름은 특수 문자나 숫자로 시작하면 안된다.

블로그 이미지

Link2Me

,
728x90

코틀린 인터페이스

- Java 와 달리 인터페이스 함수가 구현부를 가질 수도 있고, 추상함수만 가질 수도 있다.

- 상속과 마찬가지로 콜론(:)을 사용해서 인터페이스를 구현한다.

  자바에서는 클래스의 상속과 인터페이스의 구현을 extends 와 implements로 구분한다.

- 상속은 한번에 하나밖에 안되지만, 인터페이스는 콤마(,)로 여러개를 구현 가능하다.

   또한, 콜론(:)으로 동시에 클래스 상속과 인터페이스 구현이 가능하다.

- 코틀린에서는 상속받거나 구현한 함수의 앞에 무조건 override 키워드를 붙이도록 강제한다.

  Java에서는 부모 클래스의 메서드를 재정의하거나 인터페이스 구현 메서드를 @Override 어노테이션으로 구분한다.
  하지만 @Override 어노테이션 추가는 선택 사항이라 메서드의 유형을 코드만으로 구분하기는 어렵다.


fun main(args: Array<String>) {
    var a = Person()
    a.click()
    a.run()
}

interface Clickable {
    // 일반함수 : open 함수로 간주한다.
    fun click() {
        println("버튼을 눌렀어요.")
    }
}

interface Runner {
    // 추상함수 : abstract 함수로 간주한다.
    fun run()
}

class Person : Runner, Clickable {
    override fun run(){
        println("성큼 성큼 달린다.")
    }
} 


만약, 인터페이스 내의 함수들이 구현체가 있고, 중복된 함수가 있을 경우에는 어떻게 할까?

필요한 클래스의 super 를 호출할 수 있다. 둘 다 혹은 필요한 클래스의 함수만 호출해도 된다.


fun main(args: Array<String>) {
    var a = Person()
    a.click()
    a.run()
}

interface Clickable {
    // 일반함수 : open 함수로 간주한다.
    fun click() {
        println("클릭 버튼을 눌렀어요.")
    }
}

interface Runner {
    // 추상함수 : abstract 함수로 간주한다.
    fun run()
    fun click() {
        println("Runner 버튼을 눌렀어요.")
    }
}

class Person : Runner, Clickable {
    override fun run(){
        println("성큼 성큼 달린다.")
    }

    override fun click() {
        super<Clickable>.click()
        super<Runner>.click()
    }
}
 


'안드로이드 > Kotlin 문법' 카테고리의 다른 글

코틀린 접근 제한자  (0) 2020.01.14
코틀린 패키지  (0) 2020.01.13
코틀린 추상클래스  (0) 2020.01.12
코틀린(Kotlin) 클래스 선언 및 상속  (0) 2020.01.12
코틀린 기본 이해  (0) 2020.01.07
블로그 이미지

Link2Me

,
728x90

추상 클래스

- 클래스와 일부 멤버가 abstract로 선언되면 추상 클래스이다.
- abstract 키워드 사용시 클래스나 함수에 open 키워드를 따로 명시하지 않아도 된다.
- abstract 함수는 선언부분만 있고 구현부가 없다.

  추상 함수는 상속받은 서브 클래스에서 override하여 재정의해야 한다.
- 다중 상속은 불가능하다.


※ 추상 클래스는 미완성 설계도이다. 미완성 설계도로는 제품을 만들 수가 없다.

   클래스는 직접 객체 생성(인스턴스화)을 할 수 있지만, 추상 클래스는 직접 객체 생성을 할 수가 없다.

   반드시 상속을 받는 자식 클래스가 있어야만 비로소 객체를 생성할 수 있다.


fun main() {
    var b = Dog("불독", 5)

    b.introduce()
    b.bark()
    b.sniff()

    var c = Cat("나갈래", 4)
    c.introduce()
    c.meow()
    c.sniff()
}

abstract class Animal(var name:String, var age:Int, var type:String){
    abstract fun introduce()
    fun sniff(){
        println("냄새를 맡느라고 끙끙거린다.")
    }
}

class Dog(name:String, age:Int) : Animal (name,age,"개"){
    override fun introduce(){
        println("타입 : Dog, ${name}, ${age}살 입니다.")
    }

    fun bark(){
        println("멍멍멍")
    }
}

class Cat(name: String, age: Int) : Animal(name, age, "고양이"){
    override fun introduce(){
        println("타입 : Cat, ${name}, ${age}살 입니다.")
    }

    fun meow() {
        println("야옹야옹")
    }
}


예제2) 출처 : https://www.programiz.com/kotlin-programming/abstract-class

abstract class Person(name: String) {
init {
println("My name is $name.")
}
// 일반 메서드
fun displaySSN(ssn: Int) {
println("My SSN is $ssn.")
}
// 추상 메서드
abstract fun displayJob(description: String)
}

class Teacher(name: String): Person(name) {
// 추상 메서드 구현
override fun displayJob(description: String) {
println(description)
}
}

fun main(args: Array<String>) {
val jack = Teacher("Jack Smith")
jack.displayJob("I'm a mathematics teacher.")
jack.displaySSN(23123)
}


'안드로이드 > Kotlin 문법' 카테고리의 다른 글

코틀린 접근 제한자  (0) 2020.01.14
코틀린 패키지  (0) 2020.01.13
코틀린 인터페이스  (0) 2020.01.13
코틀린(Kotlin) 클래스 선언 및 상속  (0) 2020.01.12
코틀린 기본 이해  (0) 2020.01.07
블로그 이미지

Link2Me

,
728x90

코틀린 클래스 선언

class 클래스명(변수) { }

코틀린은 자바, C++과는 달리 클래스 선언 부분에서 이름에 괄호를 붙여 생성자를 만들 수 있다.

자바는 멤버변수를 field라고 하지만 코틀린 프로퍼티라는 용어를 사용한다.
자바는 생성자를 꼭 정의해야 하지만 코틀린은 생략이 가능하다.

코틀린에는 주 생성자와(primary constructor)와 부생성자가(secondary constructor)가 존재한다.
주 생성자는 class 선언과 함께 선언하고, 부 생성자는 추가적인 생성자가 필요할 때 사용한다.
생성자를 정의하지 않으면 기본으로 인자가 없는 생성자를 만들어 준다.

부모의 생성자는 super(), 클래스 내 생성자중 다른 생성자는 this()로 호출이 가능하다.


fun main() {
    var a = Person("박보영", 1990)  // 코틀린은 new 키워드 없이 인스턴스를 생성한다.
    var b = Person("전영경",1997)
    var c = Person("차은우")
    var d = Person("홍길동")

    //println("안녕하세요, ${a.birthYear}년생 ${a.name} 입니다.")
}

class Person (var name:String, val birthYear:Int) {

    // var name:String, val birthYear:Int

    // 프로퍼티 선언 및 초기화는 기본 생성자에서 간결한 구분으로 사용 가능


    // 초기화
    init {

        // init 안에서는 자바처럼 [this.클래스변수= 매개변수]를 얼마든지 할 수 있다.

        println("안녕하세요, ${this.birthYear}년생 ${this.name}입니다.")
    }

    // 보조 생성자 : constructor 키워드로 선언하고 클래스 body에 구현한다.

    // 클래스 별로 여러 개를 가질 수 있다.
    constructor(name: String) : this(name,1997)
}
 

기본 생성자

- 기본 생성자에 어노테이션 접근지정자 등이 있을 경우 constructor 키워드가 필요하다.

  class Person public @Inject constructor(name: String) { .... }



클래스 상속
- 코틀린의 최상위 클래스는 Any 이다.
  Any는 java.lang.Object 와는 다른 클래스이며, equals(), hasCode(), toString()만 있다.
- 상속 키워드는 콜론(:)이다. Java 의 상속 키워드는 extends
- 코틀린의 클래스와 메소드는 기본적으로 final이다. 즉 기본적으로 상속을 못하게끔 되어 있다.
  Java에서는 클래스나 메서드에 final 키워드를 붙여 클래스를 더 이상 상속받지 못하게 하거나,
  메서드를 재정의하지 못하게 할 수 있다.
- 클래스의 상속을 허용하려면 클래스 앞에 open 변경자를 붙여야 한다.
  open 변경자가 없으면 final 로 자식 클래스에서 override가 불가능하다. 
  오버라이드를 허용하고 싶은 메소드나 프로퍼티 앞에도 open 변경자를 붙여야 한다.
- 부모 클래스의 메소드를 자식 클래스에서 오버라이드 한 경우, 해당 메소드는 기본적으로 열려있다.

fun main() {
    var a = Animal("불독", 3,"개")
    var b = Dog("불독", 5)

    a.introduce()
    b.introduce()
    b.bark()

    var c = Cat("나갈래", 4)
    c.introduce()
    c.meow()
}

open class Animal(var name:String, var age:Int, var type:String){
        open fun introduce(){ // open 이므로 override 가능하다.
        println("저는 ${type} : ${name}, ${age} 살 입니다.")
    }
}

class Dog(name:String, age:Int) : Animal (name,age,"개"){
    // 상위 클래스 함수에 open 키워드를 명시하고, 서브 클래스 함수에 override 를 붙인다.
    override fun introduce(){
        println("타입 : 개, ${name}, ${age} 살 입니다.")
    }

    fun bark(){
        println("멍멍멍")
    }
}

class Cat(name: String, age: Int) : Animal(name, age, "고양이"){
    fun meow() {
        println("야옹야옹")
    }
}
 


'안드로이드 > Kotlin 문법' 카테고리의 다른 글

코틀린 접근 제한자  (0) 2020.01.14
코틀린 패키지  (0) 2020.01.13
코틀린 인터페이스  (0) 2020.01.13
코틀린 추상클래스  (0) 2020.01.12
코틀린 기본 이해  (0) 2020.01.07
블로그 이미지

Link2Me

,
728x90

맥북 프로 2012 13인치에 사용하는 SSD 가 256GB이다보니 용량이 부족하여 500GB로 교체시에 타임머신 백업/복원을 안하고 그냥 복사툴을 이용했더니 제대로 동작되지 않는 현상이 있다.


기존

 SSD 256GB 에 macOS High Sierra + Windows10

백업

 SSD 500GB 에 타임머신 백업

 - 원래 이걸로 대체하려고 했으나, Carbon Copy TOOL 복사시

   제대로 동작하지 않는 현상으로 실패

 - 처음부터 백업용으로 사용할 HDD 등을 준비하여

   타임머신 백업을 사용하면 좋았을 듯....

현재

 SSD 1TB 에 macOS High Sierra + Windows10

 - 타임머신 복원을 이용한 macOS High Sierra 환경 복원

 - Windows10 은 구글 드라이브에 백업해둔 ISO 파일 다운로드후

   bootcamp 설치후 약 400GB 용량 할당


이번에 SSD 1TB를 구입하여, Sierra USB 디스크를 만들어서 처음부터 설치를 할까 했는데 손상되었다면서 제대로 동작되지 않는다.

타임머신 백업 기능을 이용해서 SSD 500GB에 macOS를 백업을 했다.

맥북을 부팅하면서 command + R 키를 눌러주면 Local 복구하는 화면으로 넘어갈 수 있다.


타임머신 백업 자료가 있는 디스크를 선택하고 백업날짜를 지정한 이후

설치할 디스크를 지정하면 복원이 되고 이후에 바로 macOS로 부팅이 된다.


※ bootcamp 로 나뉘어진 윈도우 영역은 복원을 할 수 없다.

    macOS 시스템 영역만 가능하다.



'iOS > MACBOOK' 카테고리의 다른 글

아이맥 애플케어플러스  (0) 2020.02.15
macOS 카탈리나  (0) 2020.01.16
아이맥 2015 중고 구입 검토  (0) 2020.01.04
맥북프로 2015 중고 구입 검토  (0) 2020.01.02
맥북 기본 부팅 순서 변경 방법  (0) 2019.02.14
블로그 이미지

Link2Me

,
728x90

구글이 2017년 5월 18일 안드로이드 공식 언어로 코틀린(Kotlin) 추가해서 현재 Android 개발은 Java 와 Kotlin 이 공존하고 있는데, 향후에는 Kotlin 으로 전부 대체될 것으로 보인다.

GitHub 에서 source code를 검색하면 Kotlin 으로 된 코드들이 검색되어 안배우면 안되겠다 싶어서 동영상 보면서 정리를 할 생각이다. 배울 언어가 너무 많아서 안배우고 싶은데, 안배우면 도태될 거 같아서....

 

Kotlin 은 IntelliJ IDE를 만든 JetBrains 에서 개발한 오픈소스 언이이다.

JVM에서 동작하고 Java 와 100% 호환된다.

Java 코드를 Kotlin 에서 인식하고, Kotlin 코드를 Java 에서 인식한다.

 

- Java 플랫폼에서 숫자형은 JVM primitive type 으로 저장됨
- Nullable 이나 제네릭의 경우에는 박싱됨
- 박싱된 경우 identity를 유지하지 않음.
- 문자(Characters) : 숫자로 취급하지 않음.

 

개발툴 다운로드

- 온라인에서 코드 테스트 : https://play.kotlinlang.org/ 에서 간단한 코드를 연습할 수 있다.

- Intellij IDEA 개발툴 : https://www.jetbrains.com/ko-kr/idea/ 에서 community 무료버전을 다운로드 받아서 설치한다.

  Java 에 대한 코드 연습을 Eclipse 툴에서 하듯이

  유투브 강좌 등에서 설명하는 코틀린 문법 연습은 IntelliJ IDEA 툴에서 하면 된다.

  Android Studio 에서 코틀린 선택하여 코드 연습하는 것은 적절하지 않다.

TOOL을 Jetbrains 에서 만들어서 Android Studio 와 메뉴구조는 비슷하다.

잠깐 써본 PHPStorm 도 메뉴구조가 거의 동일하더라.

 

변수의 선언

Java에서는 변수를 선언할 때 타입이 맨 앞에 온다. 코틀린에서는 타입 지정을 생략하는 경우가 흔하다.
Java에서는 두가지종류의 변수가 있는데 하나는 primitive type(기본형)이 있고 다른 하나는 레퍼런스 타입(객체형)이 있다. 코틀린에서는 이 모든게 통합됬다. 즉 레퍼런스 타입밖에 없다.
 

Java에서는 기본이 변수고 상수는 final을 붙혀서 표시했다.

코틀린에서는 변수는 var로 상수는 val로 표시한다.

val // 변경 불가능한 참조를 저장하는 변수다. 선언시에만 초기화 가능. 중간에 값을 변경할 수 없다.

var // 변경 가능한 참조다. 일반적으로 통용되는 변수, 언제든지 읽기쓰기가 가능하다.

 

 

기본적으로 모든 변수를 val 키워드를 사용해 불변 변수로 선언하고, 나중에 꼭 필요할 때에만 var 변수로 변경하라.

코틀린은 문장의 끝에 세미콜론을 사용하지 않는다.

코틀린은 기본변수에서 null 을 허용하지 않으며, 또한 변수에 값을 할당하지 않은채로 사용하게 되면 문법 에러를 표시하고 컴파일을 막아주므로 의도치 않은 동작이나 null pointer exception 등을 원천적으로 차단해 준다는 장점이 있다.

 

var a = 100

또는

var a: Int  // 초기화 식을 사용하지 않고 변수를 선언하려면 변수 타입을 반드시 명시해야 한다.

a = 100

 

※ var 키워드를 사용하면 변수의 값은 변경할 수 있지만 변수의 타입은 고정돼 바뀌지 않는다.

var a = 100

a = "kotlin"  ← 컴파일 오류 발생

컴파일러는 변수 선언 시점의 초기화 식으로부터 변수의 타입을 추론한다.

 

var a: Int? // 코틀린에서 null 값을 허용하려면 자료형의 오른쪽에 ? 기호를 붙여준다.

 

문자형 : 코틀린은 문자열을 유니코드 인코딩 방식 UTF-16 BE 을 사용하여 글자 하나당 2bytes 메모리 공간을 차지한다.

var a = '가' // 문자 한글자는 작은 따옴표 사용한다.

var a ="홍길동" // 문자열을 쌍따옴표를 사용한다.

var a ="""여러줄의

   문자열"""  // 쌍따옴표 3개를 사용하면 여러줄 문자열 가능하며, 줄바꿈이나 특수문자까지 사용 가능하다.

 

lateinit 키워드를 사용한 늦은 초기화

코틀린에서는 클래스의 변수(var, val로 선언되는 변수들)를 프로퍼티(Property)라 부른다.

코틀린에서는 일반적으로 생성자에서 모든 프로퍼티를 초기화해야 한다.

프로퍼티 타입이 null이 될 수 없는 타입이라면 반드시 null이 아닌 값으로 그 프로퍼티를 초기화해야 한다.

private var backPressHandler: BackPressHandler? = null

// null로 초기화하기 위해 null이 될 수 있는 타입인 프로퍼티를 선언한다.

backPressHandler!!.onBackPressed()

// 반드시 null 가능성을 신경써야 한다. non-null 단언 연산자 !!를 꼭 써야 한다.

 

lateinit 변경자를 붙이면 프로퍼티를 나중에 초기화할 수 있다.

private lateinit var backPressHandler: BackPressHandler

// 초기화를 하지 않고 null이될 수 없는 프로퍼티를 선언한다.

backPressHandler.onBackPressed()

 

lateinit은 다음 조건에서만 사용할 수 있다.
1) var 변수에서만 사용한다.
2) null 값으로 초기화 할 수 없다.
3) 초기화 전에는 변수를 사용할 수 없다.
4) Int, Long, Double, Float에는 사용할 수 없다.

5) lateinit은 custom getter/setter를 사용하지 않은 프로퍼티에만 사용할 수 있다.

문자열 접합 연산

println("안녕하세요, $name!")  → Java의 문자열 접합 연산 ("안녕하세요," + name + "!")와 동일한 기능

 

존재하지 않는 변수를 문자열 템플릿 안에서 사용하면 컴파일 오류가 발생한다.

$ 문자를 문자열에 넣고 싶다면 println("\$x")와 같이 \를 사용해 $를 이스케이프 시켜야 한다.

${name} 처럼 중괄호로 변수명을 감싸는 습관을 들이면 좋다. 이렇게 하면 복잡한 식도 중괄호로 둘러싸서 문자열 템플릿안에 넣을 수 있다.

 

 

형변환

코틀린에서는 Int 형과 Long 형 타입이 다른 경우 자동으로 형변환이 되지 않는다

즉, 다른 언어들이 지원하는 암시적 형변환은 지원하지 않고, 명시적 형변환만 지원한다.
  var a: Int = 100
  var b: Long = a.toLong()

 

배열

배열은 Array 클래스로 표현된다.

var intArr = arrayOf(1, 2, 3, 4, 5)  // arrayOf 함수를 통해 배열에 저장할 값들을 나열한다.

var intArr = arrayOfNulls<Int>(10) // null 로 채워진 배열. 

 

함수

function 의 약자인 fun 을 사용한다.

 

리턴과 파라미터가 없는 함수
fun 함수이름() { }

값을 리턴 하는 함수
fun 함수이름() : 리턴타입 { return 값 }

리턴과 파라미터가 있는 함수
fun 함수이름( 변수이름: 변수타입) : 리턴타입 { return 값 }

fun add(a: Int, b: Int, c: Int): Int {   // 반환형

    return a + b + c

}

단일표현식 함수 

fun add(a: Int, b: Int, c: Int) = a + b + c  // 반환형의 타입 추론이 가능하여 반환형을 생략할 수 있다.

 

IF문

- val max = if( a > b) a else b

  Java 의 삼항연산자(ternary)가 코틀린에는 없음.

  int max = (a > b) > a : b; // Java 의 삼항연산자

- If식의 branches 들이 블록을 가질 수 있음 {  }

  val max = if(a > b) {

    print("Choose a")

    a

  } else {

    print("Choose b")

    b

  }

 

다중 조건문 when

- when문은 C계열 언어의 switch 문에 대응한다.

- when문은 각각의 branches의 조건문이 만족할 때까지 위헤서부터 순차적으로 인자를 비교함.

  when (x) {

     1 -> print("x == 1")

     2 -> print("x == 2")

     else ->{

           print("x is neither 1 nor 2)

     }

  }

- when이 식으로 사용된 경우 else 문이 필수임

- when 이 식으로 사용된 경우 컴파일러가 else문이 없어도 된다고 입증할 수 있는 경우에는 else 생략 가능

  var res = when (x) {

    true -> "맞다"

    false -> "틀리다"

  }

- branch의 조건문에 콤마를 사용하여 여러조건들을 처리할 수 있다.

  when (x) {

     0, 1 -> print("x == o or x == 1")

     else -> print("기타")

  }

- branch의 조건문에 함수나 식을 사용할 수 있다.

  when (x) {

     parseInt(x) -> print("s encodes x ")

     1 + 5 -> print("6")

     else -> print("s does not encode x")

  }

- range 나 collection 에 in 이나 !in 으로 범위 등을 검사할 수 있다.

  val validNumbers = listOf(3, 6, 9)

  when (x) {

    in validNumbers -> print("x is valid")

    in 1..10 -> print("x is in the range")

    !in 10..20 -> print("x is outside the range")

    else -> print("none of the above")

  }

- is 나 !is 를 이용하여 타입도 검사할 수 있다.

  fun hasPrefix(x: Any) = when (x) {

is String -> x.startsWith("prefix")

else -> false

  }

- when 에 인자가 없으면, 논리연산으로 처리된다.

  when {

x.isOdd() -> print("x is odd")

x.isEven() -> print("x is even")

  }

 

For Loops

- for문은 iterator 를 제공하는 모든 것을 반복할 수 있다

  for(item in collection)

      print(item)

- for문의 body가 블록이 올 수도 있다.

  for(item in collection) {

     print(item.id)

     print(item.name)

  }

- for(i in 0..9)  // 0부터 1씩 증가시키며 반복한다.

  for(i in 0..9 step 3)  

     print(i)    // 3씩 증가되어 0, 3, 6, 9 를 출력한다.

- 감소 반복

  for(i in 9 downTo 0)   // 9부터 1씩 감소하여 반복한다.

  for(i in 9 downTo 0 step 3)  // 9부터 3씩 감소하여 반복한다.

- 문자 for 문

  for(i in 'a'..'f')   // a부터 f까지 반복한다.

- 반복문 탈출 break

  loop@for(i in 1..10){

     for(j in 1..5) {

         if(i == 1 && j == 2) break@loop

         println("i : $i, j : $j")

     }

  }

 

fun main(args: Array<String>) {
    var a = listOf(1, 2, 3, 4, 5)
    println(a)
    println(sum(3 , 4))
    foo()
    println("")
    foo2()
    println("")
    foo3()
    println("")
    foo4()
    println("")
    println(foo5())
}

fun sum(a: Int, b: Int):Int {
    return a + b
}

fun foo() {
    var ints = listOf(0, 1, 2, 3)
    ints.forEach(
            fun(value: Int){
                if(value == 1) return
                print(value)
            })
    print("End")
}

fun foo2() {
    var ints = listOf(0, 1, 2, 3)
    // 람다식에서 return 시 nearest enclosing 함수가 return 된다.
    ints.forEach {
                if(it == 1) return
                print(it)
            }
    print("End")
}

fun foo3() {
    var ints = listOf(0, 1, 2, 3)
    // 람다식에 대해서만 return 하려면 label 을 이용해야 한다.
    ints.forEach loop@{
                if(it == 1) return@loop
                print(it)
            }
    print("End")
}

fun foo4() {
    var ints = listOf(0, 1, 2, 3)
    // 람다식에 대해서만 return 하려면 label 을 이용해야 한다.
    // 암시적 레이블은 람다가 사용된 함수의 이름과 동일하다.
    ints.forEach {
        if(it == 1) return@forEach
        print(it)
    }
    print("End")
}

fun foo5(): List<String> {
    var ints = listOf(0, 1, 2, 3)
    val result = ints.map{
        if(it == 0){
            return@map "zero"
        }
        "No $it"
    }
    return result
}
 

 

 

'안드로이드 > Kotlin 문법' 카테고리의 다른 글

코틀린 접근 제한자  (0) 2020.01.14
코틀린 패키지  (0) 2020.01.13
코틀린 인터페이스  (0) 2020.01.13
코틀린 추상클래스  (0) 2020.01.12
코틀린(Kotlin) 클래스 선언 및 상속  (0) 2020.01.12
블로그 이미지

Link2Me

,
728x90

아래 내용은 네이버 지식IN에 애플 대리점에서 답변한 내용을 중심으로 정리했고 SSD 교체는 사설 맥수리점에서 답변한 내용을 포함하고 있다.

아이맥 2016년형은 모델 자체가 없다. 아이맥 2015, 아이맥 2017, 아이맥 2019

아이맥 2014부터 모니터 해상도가 5K를 지원하는 걸로 변경되어, 사설 맥수리점에서도 최소 2015 제품을 추천하더라.

아이맥 2013, 2012는 2K 이므로 해상도가 떨어진다는 것이다.

애플 센터에 문의해보니 공식적인 A/S는 2013년도 제품까지는 A/S 대상이 아니라고 한다.

매년 증가되는 걸 고려하면 최소한 2017년 이상 iMAC, 맥북 프로 등을 구입하는 것이 좋을 거 같다.

SSD는 애플 센터를 통한 교체는 안된다고 하므로 사설 수리점에서만 교체가 가능하므로 처음부터 1TB를 고려하는 것이 좋을 듯 하다.



성능 벤치 마크

https://browser.geekbench.com/mac-benchmarks


아이맥 2019 i9 3.6GHz 1249
아이맥 2019 i5 3.7GHz 1139
아이맥 2019 i5 3.1GHz 1069
아이맥 2019 i5 3.0GHz 1021
아이맥 2017 i7 4.2GHz 1126
아이맥 2015 i7 4.0GHz 1046
아이맥 2017 i5 3.8GHz 1028
아이맥 2017 i5 3.5GHz 999
아이맥 2017 i5 3.4GHz 921
아이맥 2015 i5 3.3GHz 934
아이맥 2015 i5 3.2GHz 861
맥북프로 2019 i9 2.4GHz 1129
맥북프로 2019 i9 2.3GHz 1099
맥북프로 2019 i7 2.6GHz 1037
맥북프로 2018 i7 2.6GHz 1011
맥북프로 2017 i7 3.1GHz 929
맥북프로 2017 i7 2.9GHz 899
맥북프로 2017 i7 2.8GHz 865
맥북프로 2015 i7 2.5GHz 862
맥북프로 2015 i7 2.2GHz 794


4.0GHz 쿼드 코어 Intel Core i7

- 2015년 10월 출시 아이맥 27"는 스카이레이크 쿼드코어 CPU

- 2017년 6월 출시 아이맥 27"는 카바레이크 쿼드코어 CPU (한단계 높은 CPU)

- i7 CPU는 가상의 코어를 8코어로 늘려서 실제 작업 성능은 같은 세대 i5 CPU대 비 30~40% 성능향상
iMac Retina 5K 디스플레이

5120 x 2880 해상도로 10억 색상 지원
382 니트 밝기 (2017년 아이맥 500 니트 밝기)

세로: 51.6cm
가로: 65.0cm
스탠드 깊이: 20.3cm
무게: 9.54kg

전압: 100 ~ 240V AC
주파수: 50 ~ 60Hz(단상)
작동 온도: 10°C ~ 35°C
상대 습도: 5% ~ 95% 미응결
작동 고도: 3000m까지 테스트

1867 MHz PC3-14900 DDR3 노트북용 메모리 사용 : 8GB X 4 개 장착 가능 (비공식 16GB X 4 가능)

Thunderbolt 2 포트 2개
Mini DisplayPort 출력
HDMI, DVI, VGA 및 듀얼 링크 DVI 지원(어댑터 별매)

Magic Keyboard
Magic Mouse 2
Magic Trackpad 2

Bluetooth 4.0 무선 기술


아이맥 2015는 오로지 내장 하드에만 윈도우 설치가 가능하고 외장하드에 윈도우 설치해서 부팅은 불가능하다.

아이맥은 중고/신제품 으로 구입시 반드시 SSD로 되어 있는 중고를 구입하는게 좋다.

새제품으로 구매시에는 SSD로 업그레이드 주문(CTO)을 해서 구매해야 한다.

요즈음에는 SSD 1TB 정도는 되어야 iOS 와 Windows10 을 같이 사용하는데 좋을 거 같다.

물론 디자인 전문적으로 하거나, 음악 전문으로 하는 분은 SSD 500GB로도 충분할지는 모르겠다.


Type-C 규격은 '15년 말 규격 표준화 되어, '16년 이후 본격적으로 적용 제품이 출시되기 시작하였다.
참고로 아이맥 2015 5K 및 맥북 2015" Pro는 Type-C 지원 않는다.


외장 그래픽카드가 없다면 4K 영상작업 힘들다.

음악 작업용은 화면이 클수록 좋다.

음악 프로그램은 많은 창을 열고 작업을 해야 하며, CPU 처리 성능이 중요하므로 6 Core 가 더 좋다.

많은 가상 악가를 사용하기 위해서는 메모리가 넉넉해야 한다.

많은 음원들, 많은 가상악기등을 저장하고 수시로 불러와서 작업을 해야하므로 하드 공간이 넉넉해야 한다.


부트 캠프 설치 준비사항

- 내장 SSD 또는 HDD에만 설치 가능하다.

- 신형 아이맥은 윈도우7은 설치가 불가능하다.

- USB 메모리 없이 윈도우 설치가 가능하다.

- 윈도우 10 x64.ISO 파일

- ISO을 복사해 놓고 유틸리티 폴더안에 부트캠프 지원에서 시키는 데로 진행만 하시면 윈도우 설치가 가능하다.



인터넷 복구 모드 부팅 설치 방법

1. 맥 전원을 끈다(전원버튼을 길게 5초이상 눌러 전원을 끈다)
2. 다시, 맥 전원버튼 누르자 마자 [커맨드+쉬프트+옵션+R키]만을 길게 눌러 [인터넷 복구]모드 부팅한다
3. [인터넷 복구]모드로 부팅이 되면, [디스크 유틸리티]를 실행한다.
4. 왼쪽에서 내장하드를 선택후 우측의 지우기 부분에서 [맥OS확장저널링 또는 APFS]으로 지우기를 한다.
5. [디스크 유틸리티]를 종료하고, 맥OS 설치한다.


기존 계정 삭제

- 필요한 자료는 먼저 백업을 한다.

- [시스템 환경설정]의 [사용자 및 그룹]열고..하단 자물쇠 풀고..기존 계정 선택후 [-]누른후,

  [홈 폴더 삭제]를 선택해서 지운다.


새 사용자 계정 추가

- [시스템 환경설정]의 [사용자 및 그룹]열고..하단 자물쇠 풀고..[+]눌러서...

  새로운 사용자 계정(관리자모드)을 추가한다.
- 애플메뉴에서 로그아웃...새 사용자 계정을 로그인해서 사용한다.


중고모니터

- http://kmug.co.kr/ 에서 검색한다.

- http://cafe.naver.com/inmacbook 에서 검색한다.

- http://www.tomatomac.com/ 에서 검색한다.

- 24인치 애플시네마 LED 모니터, Mini DP port 타잎
- 27인치 애플시네마 LED 모니터, Mini DP port 타잎


액정교체

- 액정은 부분 수리가 안되고 통째로 교체가 A/S 이다.

- 액정 교체 비용은 2014 이후는 50만원, 2013은 40만원으로 검색 되었다.


중고구매시 검토사항

- 외관상태, 메모리 양, 내장하드 용량과 내장하드 상태 확인

- 중고아이맥 구매시 백색화면에서 클라우드 확인은 필수

- 모니터에 베드픽셀 유무 확인

- 키보드 정상 동작 여부 확인

- 맥부팅시 옵션키 눌러서 펌웨어 암호 유무 상태 확인

- 시스템 리포트를 통한 하드웨어 사양 확인

- 맥 원래 주인 계정으로 제품인증이 되어져 있는것을 애플 아이튠즈에서 기계 인증해제 요청


SSD 교체

- 애플 대리점에서는 아이맥 구입전 CTO 주문을 통한 SSD로 교체 주문만 가능하고 구매후에 교체 대행은 안하고 있다.

- CTO 는 애플 SSD가 장착된다.

- 아이맥 27"는 속도가 8배이상 느린 3.5" 데스크탑 하드를 사용하기 때문에 초기 구입시 SSD 교체가 중요하다.

- 같은 CPU를 사용하는 맥북프로 15" 2015보다도 실제 체감 속도는 아이맥 2015가 좀더 빠르다.

- 애플에서 플래시 SSD로 CTO 주문을 한거라면 기본 3.5" 하드 자리가 비워져 있다.

- 시중 판매되는 PCIe 방식은 아이맥에 있는  SSD 장착 포트의 핀수와 크기가 달라서 맞지 않는다.

  3.5인치 하드 디스크 제거하고 2.5인치 SSD로 교체해야 한다.

  추가 장착한 하드에 부트캠프 방식으로 윈도우 설치도 가능하다.

  그러나 분해시 기스가 좀 나고 워런티 스티커 부분을 제거해야 되기 때문에

  임의로 분해한것으로 간주되어 무상 A/S를 받을 수가 없다.

- 애플 호환용 NVMe M.2 방식 SSD나 SATA 방식이나 둘다 장착은 가능하다.

  단, SATA SSD는 기존에 장착된 HDD를 제거한 뒤 설치해야 한다.

- SSD도 오래되면 속도가 처음속도의 반도 안나온다.


중고 제품 구매시 PCI-Express SSD 인지 2.5인치 SSD인지 구별하는 것이 필요하다.

같은 SSD라도 속도 차이가 많이 난다.

애플 순정 PCI-Express SSD는 1TB 기준 70만원 정도 하는데 2.5인치 SSD는 16만원이면 살 수 있다.

사설 수리점에서 M.2 SSD로 교체해주는 것도 2.5인치 SSD에 비해서 속도가 4~5배 빠르다.




'iOS > MACBOOK' 카테고리의 다른 글

macOS 카탈리나  (0) 2020.01.16
맥북프로 SSD 교체 및 백업/복구  (0) 2020.01.08
맥북프로 2015 중고 구입 검토  (0) 2020.01.02
맥북 기본 부팅 순서 변경 방법  (0) 2019.02.14
맥북 프로 2010 메모리 증설  (0) 2019.02.14
블로그 이미지

Link2Me

,
728x90

맥북PRO 2015 16G 를 구입하여 SSD 만 1TB로 교체하여 사용하려고 검색한 결과를 적어둔다.


애플이 2013년부터 SATA 기반이 아닌 PCI 익스프레스 기반의 SSD를 맥북에 탑재하면서 저장장치 성능은 빨라졌지만 기판과 커넥터가 애플 독자 규격으로 설계되면서 맥북을 구매할 때 용량이 높은 SSD를 선택하지 않는 한 업그레이드가 어려웠다.

애플은 2015 맥북 제품부터 자체 설계한 'AP' 컨트롤러를 탑재한 PCIe x4 레인 방식의 SSD를 사용하고 있다.
덕분에 2015 제품의 순차 읽기∙쓰기 속도가 크게 개선된 바 있다.



정밀 청소와 배터리 교체만 해줘도 맥북 오래 사용할 수 있다.
2015 맥북프로 15인치 배터리 용량은 8755mh 이다.
15형 맥북 프로 Mid 2015 레티나 모델로 2015년 9월에서 2017년 2월 사이에 주로 판매된 제품에서 문제가 있어 리콜을 해주고 있다.


15년 맥북프로 15인치 공식 배터리 교체비 : 249,000원
애플은 내장 키보드 있는 상판을 통으로 교체한다.
정확한 금액은 아래에서 가까운 지역 애플 서비스센타로 방문 문의한다.


→ 상판교체를 한 것인지에 대한 정보를 확인한다.


SSD 교체 검토

맥북프로 레티나 기종은 SSD 저장장치 이외에 업그레이드 불가능하다.
2017 터치바 모델은 SSD 저장장치 교체도 불가능하다.
판매되는 2.5인치 SSD가 아닌 스틱형의 SSD를 사용하여 가격이 상당히 비싸다.

트랜센드 JetDrive 820 960GB 가격은 61만원 정도 된다.

트랜센드 JetDrive 850 960GB 가격은 70만원 약간 넘는다. (2020년 1월 2일 옥션 사이트 기준)


사용후기를 찾아보면
아마존에서
- Samsung 970 EVO 1TB - NVMe PCIe M.2 2280 SSD (Plus 를 사면 절대 안됨)
- Sintech NGFF M.2 nVME SSD Adapter Card for Upgrade 2013-2015 Year Macs
를 구입하여 직접 증설한다.
증설방법은 유투브에 동영상으로 나온다.
증설시 배터리 전원선을 반드시 뽑고 진행해야 한다.


또다른 방법

https://eshop.macsales.com/shop/ssd/owc/macbook-pro-retina-display/2013-2014-2015 에 OWC SSD Upgrade Kit를 판매하고 있다.

해외구매이므로 OWC 온라인 스토어를 통해 주문할 수 있고 Express 배송비를 추가하면 될 것이다.


삼성전자 970 EVO M.2 2280 2TB 가격 60만원 정도 (현금가 기준, 2020년 1월 2일 기준)


How to Fix macOS Mojave Battery Draining Issue

https://iamskim.tistory.com/48 참조하면 잠자기 모드 문제점 해결 방법이 제시되어 있다.




블로그 이미지

Link2Me

,