20111222 :: 트위터 스팸DM 링크를 클릭 후 대처법

예전에도 한 번 올렸던 포스팅이지만, 트위터 세팅 페이지의 UI가 변경되어 다시 올려본다. 트위터에서 스팸 DM이 왔을 때 무심코 거기 링크를 클릭하면 자기도 모르는 사이에 스팸봇에게 자신의 트위터 계정을 연동시키는 결과를 초래한다. 덕분에 자신을 팔로하고있는 사람들도 스팸 DM에 시달리게 된다.

흔히, 이런 경우를 당하고 비밀번호만 바꾸라는 사람들이 있는데, 트위터의 외부 API는 토큰을 통해 인증을 하므로 한 번 인증되면 트위터 비밀번호와는 상관없이 계속 접근이 된다. 의심이 된다면 지금 한 번 트위터 비밀번호를 바꿔보시라. 그래도 아이폰 트위터 앱등을 통해서 그래도 트위터를 쓸 수 있다. 스팸봇도 똑같은 원리이므로 비밀번호를 바꾸는 것만으로는 스팸봇의 접근을 막을 수 없다.따라서 승인된 스팸봇의 연결을 해지하는 작업이 필수적이다.

트위터 우측 상단의 사람모양 아이콘을 클릭하여 Settings를 선택한다. 그러면 위의 그림과 같은 페이지가 나오는데, 여기서 Applications를 선택한다. 이 곳에는 자신의 트위터 계정과 연동되어 있는 앱들이 꽤 많이 나온다. 연동을 해제하고 싶다면 각 앱의 오른쪽에 있는 Revoke Access 버튼을 클릭하면 해당 앱의 접근이 차단된다. 사용하는 앱의 연결을 해제하면, 해당 앱에서 다시 비밀번호를 입력하고 승인 절차를 거치면 다시 사용할 수 있으므로 거침없이 클릭하자.

의외로 생각보다 엄청나게 많은 앱이 연동되어 있을 것인데, 종종 한 번씩 싹 해제해버리는 것도 나쁜 습관은 아닐 것 같다. 또한 간혹 스팸봇의 인증 과정에서 비밀번호를 털리는 경우도 있을 수 있으므로 비밀 번호도 바꿔주는 것이 좋다.

또한 참고로 페이스북에도 이런 스팸봇이 엄청나게 많다. 흔한 예로 최다 방문자 순위를 매겨준다는 앱들이 있는데, 모두 사기앱이다. 페이스북은 방문자 개념이 없는 듯 하고 (싸이와는 달리 다른 사람의 프로필을 꼭 가지 않더라도 소식 열람이 가능하므로) 있다 한 들 이를 앱에게 제공하는 API 따위는 없다. 그저 스스로를 홍보하는 글을 매일 올려 스팸 포스트만 양산하게 되므로 모두 지워버릴 것을 추천한다. (Privacy Setting의 Application 항목을 참고할 것)

20111222 :: 구글 상단 막대 변경하기

위키트리에 구글 크롬 익스텐션까지 설치해가시면서 바꾸는 방법이 소개되어 있던데… 그냥 간단하게 크롬, 파이어폭스, 사파리 등 모든 브라우저에서 적용하는 방법

1
javascript:document.cookie="PREF=ID=03fd476a699d6487:U=88e8716486ff1e5d:FF=0:LD=en:CR=2:TM=1322688084:LM=1322688085:S=McEsyvcXKMiVfGds; path=/;domain=.google.com";window.location.reload();

위 코드를 긁어서 (더블 클릭하면 전체 선택이 됨) 복사한 다음, 구글 홈페이지로 가서 주소창에 붙여 넣고 엔터.

20111207 :: [iOS] 저장이 가능한 간단 메모장

iOS 앱이 데이터를 저장하는 방법

많은 튜토리얼에서 간단한 아이폰 앱을 만드는 방법을 설명하고 있는데, 이런 튜토리얼을 따라서 이것 저것 만들어 보는 것 또한 재미도 있고, 또 여러가지 테크닉을 익힐 수 있지만 정작 활용이 가능한 앱을 만드는 것은 쉽지 않다. 이 글 (과 아마도 이어질 글들)에서는 메모장과 같이 간단히 입력한 텍스트를 저장하는 앱을 만들어 보는 것을 함께 알아보고자 한다. 혼자 삽질과 염탐(?)을 거듭하여 알아낸 내용들을 정리하는 차원이기도 하니 아주 자세하게는 아니지만 소상히 쓰려고 노력할 것이다.

iOS 앱이 어떤 데이터를 영구적으로 보관하는 방법에는 사실 여러가지가 있는데 대략 다음과 같은 방법들이 있다.

  • 코어데이터
  • SQLite
  • 아카이빙(직렬화)
  • 프로퍼티 리스트

코어데이터

코어데이터는 데이터를 저장소에 읽고 쓰고 또 관리하는 전반적인 기능을 제공하는 프레임워크이다. 코어데이터는 저장 방법을 아카이브 또는 데이터베이스(SQLite)로 사용할 수 있고, 변경 사항을 쉽게 추적하여 저장하고 또 저장된 객체를 불러와서 자동으로 관리해주는 다양한 기능들을 제공한다. 이를 잘 사용하면 엄청나게 많은 양의 코드를 손쉽게 줄일 수도 있다. 하지만 이 프레임워크는 결정적으로 초보자가 사용하기에는 조금 어렵다. 코어데이터 프레임워크 자체의 개념 자체가 초보자에게는 낯설기 때문이나, 실질적으로 예제를 만들어보면 허무할만큼이나 간단하게 데이터를 처리해준다.  예를 들어 사용자가 편집한 변경사항을 자동으로 기록한다거나 하는 것들을 지원한다.

코어데이터는 OSX용 앱을 제작할 때 코코아 바인딩과 결합하면 “한 줄의 코드도 작성하지 않고” 데이터를 불러오고 편집하고 저장하는 앱을 만드는 것이 가능할 정도의 모든 기능을 제공해주므로 시간이 될 때 꼭 공부해볼 것을 권장하며, 이 연재의 마지막에는 코어데이터를 사용하여 메모앱을 작성하는 방법을 살펴볼 것이다.

SQLite

SQLite는 아이폰에도 내장되어 있는 경량 데이터베이스 엔진이다. 개인적으로는 초보자에게 차라리 코코아 프레임워크를 권하고 싶다. 코코아터치에 포함되어 있는  SQLite3 프레임워크는 대부분 C 형식의 함수를 사용하고 있고 데이터 입출력시에는 일일이 쿼리 문을 작성해야 하므로 SQL에 대한 지식도 알고 있어야 하는 데 난점이 있다. 단, 사전이나 레퍼런스와 같은 형태의 앱을 작성할 때 미리 자료를 정제하여 DB 형태로 만들기가 쉬우므로 이 경우에는 SQLite를 쓰는 것이 좋을 수도 있다.

아카이빙

아카이빙 역시 초보자들에게는 조금 어려운 개념일 수 있으나, 대부분의 표준 코코아터치 클래스들은 스스로를 인코딩하는 방법을 알고 있기 때문에 의외로 손쉽게 접근할 수 있는 방법이나, SQLite에 밀려서 많이 쓰이고 있지 않다. 이 연재에서 우선적으로 다뤄볼 기법이기도 하다.

프로퍼티 리스트

프로퍼티 리스트는 일종의 XML의 포맷으로 키-값 의 짝을 기록하는 방법이다. 이 방법으로 생성된 데이터는 별도의 프로그램 없이 사람이 확인할 수 있다는 장점이 있다. 하지만 나는 잘 모르므로 패스하겠다.

아카이빙

아카이빙은 앱이 실행될 때 서로 서로 관계를 맺고 있는 객체들을 직렬화하여 데이터 스트림으로 만드는 기법이다. 이 데이터 스트림을 파일에 저장하고 또 읽어 들이는 방법으로 사용자 데이터를 보존할 수 있다.

다행히도 많은 표준 코코아터치 클래스들은 스스로를 아카이빙하는 방법을 알고 있다. 이러한 객체들은 NSCoding 프로토콜을 따르는데, 이 프로토콜을 따르는 객체는 스스로를 아카이빙하면서 자신과 연관을 맺고 있는 모든 객체에 대해 아카이빙하라는 메시지를 보낸다. 따라서 우리는 각각의 객체가 NSCoding 프로토콜을 따르도록하고 루트 객체를 아카이빙하면 필요한 모든 객체를 아카이빙할 수 있게 된다. (이와 관련해서는 나중에 다시 살펴볼 계획이다.) 이 방식의 강점은 여러 객체를 저장하기 위해서는 이를 단순히 배열에 담고 그 배열 객체를 한 번만 아카이빙하면 마치 전염병처럼 메시지가 번져나가 모든 객체를 아카이빙 할 수 있다는 것이다. 또한 단순한 값이 아닌 바이너리 데이터도 파일에 함께 그대로 저장할 수 있다는 강점이 있다.

객체를 아카이빙하기 위해서는 NSCoder 클래스를 사용한다. 하지만 NSCoder는 추상 클래스로 프로그래머가 직접 NSCoder 클래스의 인스턴스를 만드는 일은 거의 없다, 대신에 이 클래스에서 구체화된 NSKeyedArchiver 나 NSKeyedUnarchiver 클래스를 사용한다.

예제 1 – 입력된 내용을 저장하는 메모판

이 모든 이야기는 예제를 통해 확인하면 보다 쉽게 이해될 수 있다. Xcode에서 새로운 프로젝트를 만든다. 프로젝트 이름이야 다들 알아서 하시고 iOS Application에서 single view 기반의 프로젝트를 생성하자. 이는 Xcode의 버전에 따라서는 window-based 앱일 수도 있다.

프로젝트가 생성되면 스토리보드 (혹은 MainWindow) 파일이 있는데 여기에 텍스트뷰를 하나 집어 넣고 사용자가 내용을 입력할 수 있도록 속성창에서 editable에 체크를 해 준다.  또한 저장하는 액션을 호출하기 위한 버튼도 하나 달아준다. 버튼은 텍스트뷰 위에 달아도 되고 아래에 달아도 된다. 디자인은 각자 알아서 하면 될 거 같다.

이제 RootViewController.h 에는 다음의 내용에 다음 코드를 추가하자

[sourcecode language="objc"]
#import <UIKit/UIKit.h>

@interface RootViewController : UIViewController
{
NSString *dataFilePath;
}
@property (nonatomic, strong) IBOutlet UITextView *memo;
-(IBAction)saveData:(id)sender;
@end
[/sourcecode]

dataFilePath는 데이터를 저장할 파일의 경로를 담는 변수가 될 것이며, memo는 인터페이스 빌더에서 추가한 텍스트뷰의 아울렛이다. 파일을 저장하고 인터페이스 빌더에서 해당 텍스트뷰에 아울렛을 지정해 준다. (지정이 끝나면 nib 파일을 꼭 저장하라)

이제 이 클래스의 구현부이다. 프로퍼티를 선언했으니 맨 먼저 해줘야 하는 일이 있겠지…  @implementation RootViewController 라고 써 있는 줄 바로 아래에 다음 문장을 추가한다.

@synthesize memo;

다음은 앱이 실행되어 뷰가 로드되었을 때 바로 파일을 저장할 경로를 준비해두는 작업을 해보자. viewDidLoad 매서드를 찾아 다음 코드를 추가한다.

1
2
3
4
5
6
7
8
NSString *docsDir;
NSArray *dirPaths;
dirPaths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory
, NSUserDomainMask, YES);
docsDir = [dirPaths objectAtIndex:0];
dataFilePath = [[NSString alloc] initWithString:[docsDir
stringByAppendingPathComponent:@&quot;data.archive&quot;]];

먼저 이 구문은 그냥 그대로 쓰는 거라고 외워두면 될 정도이다. 맨 마지막 줄의 파일 이름은 꼭 data.archive로 할 필요 없고 취향에 맞게 쓰면 된다. 이 코드는 앱의 하위 디렉토리 중에서 사용자 데이터 파일이 저장되는 Documents 디렉터리를 찾고 이 속에 파일이 저장될거라고 미리 파일의 경로를 생성해 두었다는 정도가 된다. 다행히 NSString은 파일 경로를 쉽게 다룰 수 있는 메서드를 이미 가지고 있으니 천만다행.

이제 실제 저장되는 부분을 보도록 하자.

1
2
3
4
5
-(IBAction)saveData:(id)sender
{
[NSKeyedArchiver archiveRootObject:[memo text] toFile:dataFilePath];
}

좀 허무하리 만치 간단하지 않은가? NSKeyedArchiver 객체가 저장할 데이터를 아카이빙하고 파일에 저장하는 작업을 모두 처리해 준다.

이제 다시 인터페이스 빌더에서 저장 버튼을 뷰컨트롤러의 saveData 메서드에 연결해준다.

뭔가 한가지 빠진게 있는데, 저장은 했다손 치더라도 그럼 앱이 다시 열렸을 때 저장된 내용을 복원해줘야 제맛 아니겠는가. 지금은 저장만 처리했지 데이터를 읽어오는 내용은 처리하지 않았다. 그럼 다시 RootViewController.m 에서 viewDidLoad 메서드의 끝 부분에 로딩에 관련된 코드를 추가하자.

로딩과 관련해서는 다음의 액션을 취한다.

  1. 먼저 데이터 파일 경로에 파일이 있는지 확인한다음,
  2. 파일이 있으면 파일을 읽어 들인다.
  3. 읽어들인 내용을 텍스트뷰에 옮겨준다.

코드는 다음과 같다.파일을 처리하기 위해서 NSFileManager를 사용한다.

1
2
3
4
5
6
7
8
// viewDidLoad의 마지막부분
NSFileManager *fileManager = [NSFileManager defaultManager];
if( [fileManager fileExistsAtPath:dataFilePath])
{
NSString *memoData = [NSKeyedUnarchiver unarchiveObjectWithFile:dataFilePath];
memo.text = memoData;
}

사실 여기까지하면 끝인데, 한 가지만 더 추가하자. 만약 텍스트 뷰 아래에 저장 버튼을 추가했다면, 키보드가 올라오는 바람에 저장 버튼을 누를 수 없는 경우가 있을 수 있는데, 뷰의 배경을 클릭해서 키보드를 닫도록 하자. 역시 뷰컨트롤러의 구현부에 추가한다.

1
2
3
4
5
6
7
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
if( [memo isFirstResponder] ){
[memo resignFirstResponder];
}
}

끝이다. 빌드하고 실행해본다. 에뮬레이터에서 앱을 종료한 후 다시 실행해보아도 입력했던 내용이 여전히 남아 있는 것을 확인할 수 있을 것이다.

그런데 이 예제만 만들고 나면 왠지 좀 속는 기분이 든다. 만약 뷰에서 다루는 데이터가 여러 종류이고, 이를 함께 저장하려면 어떻게 하는가?  그럼 이 메모장에서 제목란을 추가해서 한 번 수정해 보도록 하자.

인터페이스 빌더에서 루트 뷰 컨트롤러의 텍스트 뷰 크기를 좀 조정해서 빈칸을 만든 다음, 여기에 텍스트 필드를 하나 추가한다. 그리고 뷰컨트롤러의 헤더에 이 텍스트 필드에 대한 아울렛을 지정하는 코드를 만들자.

1
@property (nonatomic, strong) IBOutlet UITextField *title;

헤더 파일을 저장한 다음, 인터페이스 빌더에서 이 아울렛을 실제 텍스트 필드와 연결한 후 저장한다. 다시 구현부로 간다. 추가한 property에 대해 synthesize 구문을 추가해준다.

1
@synthesize title;

이제 saveData 메서드를 바꾼다. title과 memo의 내용을 한 번에 저장할 것이기 때문에 NSString을 아카이빙하는 것이 아니라 NSDictionary로 만들어서 저장한다.

1
2
3
4
5
6
7
-(IBAction)saveData:(id)sender
{
NSMutableDictionary *dataDictionary = [[NSMutableDictionary alloc]
initWithObjectsAndKeys:title.text,@&quot;title&quot;,memo.text,@&quot;memo&quot;, nil];
[NSKeyedArchiver archiveRootObject:dataDictionary toFile:dataFilePath];
}

저장하는 방법을 바꿨으니, 불러오는 방법도 바꿔야겠지. viewDidLoad 의 마지막 부분을 아래와 같이 바꾸면 된다. NSKeyedUnarchiver를 사용하여 NSDictionary를 복원한다음, 각 키 값을 사용하여 title, memo의 내용을 복원해주면 된다.

1
2
3
4
5
6
7
8
if([filemanager fileExistsAtPath:dataFilePath])
{
NSDictionary *dataDictionary;
dataDictionary = [NSKeyedUnarchiver unarchiveObjectWithFile:dataFilePath];
memo.text = [dataDictionary objectForKey:@&quot;memo&quot;];
title.text = [dataDictionary objectForKey:@&quot;title&quot;];
}

자, 이래도 아카이빙이 어려운가?   다음 글에서는 메모 한 개가 아니라 여러 개를 만들 수 있는 앱을 어떻게 만들 것인지 알아보도록 하겠다. 긴 글 읽으시느라 고생많았다.

20111031 :: LaunchPad 아이콘이 맘대로 재정렬될 때

라이언에서 새롭게 등장한 런치패드(Launch Pad)는 마치 OSX을 아이패드와 같이 사용할 수 있도록 해주는 상당히 재밌는 녀석임에는 틀림없다. 물론 적응하기 따라서 다를 수 있겠는데, 기존의 OSX 사용자들 모두가 이 기능을 멋지다고 평가하지는 않는 듯 하다. 아무튼 멀티터치 제스쳐와 연동하여 사용하는 재미도 쏠쏠하고 좀 익숙해지면 상당히 편리하게 사용할 수 있다는 장점도 있다.

그런데 간혹, 특히 맥을 완전히 껐다가 다시 부팅하는 경우에 간혹 “정성스럽게” 순서를 맞춰놓은 런치패드 앱 아이콘이 자기 멋대로 정렬이 엉키는 문제는 정말 당혹스럽기도 하다. (물론 왠만하면 맥은 전원을 완전히 내릴 경우가 별로 없기 때문에, 이런 경우를 자주 경험하지는 않지만) 또한 Dock을 아주 심플한 상태로 유지하고 런치패드를 자주 쓰는 앱을 실행하는 도구로 사용하는 경우라면 이 곳에서 사라지지 않는 아이콘들도 참 짜증날 수 있다.

그래서 런치패드의 아이콘을 재구성하는 방법을 소개한다. 이 방법을 통해 아이콘을 재구성한 다음에는 앱 아이콘 정렬이 엉키는 문제도 해소가 되었다. (런치패드에서의 이 문제의 원인은 나도 알 수가 없으니 제대로된 해결책인지에 대해서는 자신이 없지만, 적어도 나는 그랬다.)

1. 런치패드 구성 정보

런치패드에 등록된 앱을 구성하는 정보는 SQLite라고 하는 경량 데이터베이스에 의해 관리된다. 그리고 이 정보는 Dock의 개인 설정 폴더에 db 파일로 만들어져 있다. 우리가 하고자 하는 일은 이 정보를 깨끗이 비운 다음, 앱 아이콘을 새롭게 등록하는 것이다.

2. 작업 순서

터미널을 실행한다음, Dock의 런치패드 설정 정보 폴더로 이동한다. 이 폴더의 위치는 ~/Library/Application\ Support/Dock 이다.

$cd ~/Library/Application\ Support/Dock

(App 까지 입력하고 tab 키를 누르면 이후 부분이 자동으로 완성되고 Dock 만 추가하면 된다)

이제 기존 내용을 백업해 둔다. 먼저 ls 를 해서 어떤 파일이 있는지 본다.

$ls

그럼 숫자와 문자가 혼합된 복잡한 이름의 긴 DB 파일이 하나 보인다. 이 파일을 백업해 둔다. 이 파일은 사실 없어도 문제가 안되니까 굳이 백업하지 않아도 된다. 참고로 원래 이름은 길지만 앞에 한 두 글자만 입력한 다음 tab키를 누르면 자동완성해주니까 겁먹지 말자.

$cp {원래 이름}.db {원래 이름}.db_backup

이제 SQLite를 사용해서 앱 아이콘 정보를 싹 지운다. OSX에서 기본제공하는 sqlite3라는 DB 프로그램을 사용한다. 따옴표 안의 내용을 잘 입력하자.

$sqlite3 {원래이름}.db ‘DELETE FROM apps;’

이제 변경 사항을 다시 적용하기 위해서 Dock을 재실행한다. (Dock은 죽으면 자동으로 재시작하므로, 프로세스를 죽이면 된다.)

$killall Dock

3. 런치패드로 돌아가기

여기까지 하고 런치패드로 돌아와보면, 모든 앱의 아이콘이 말끔하게 비워져 있다. 몇몇 폴더는 빈 채로 남아있다. 이제 런치패드에 원하는 프로그램의 앱을 추가하면 된다. 만약 저 빈 폴더들을 없애고 싶다면 다른 앱들을 추가하면서 그 폴더에 앱을 집어 넣었다가 다시 빼면 폴더는 정상적으로 사라지니 너무 걱정하지 말자.

4. 런치패드에 아이콘 추가하기

런치패드에 앱 아이콘을 추가하려면 우선 Dock에 런치패드 앱을 올려두어야 한다. 런치패드 앱을 비롯한 거의 모든 앱의 아이콘은 Application 폴더에 있으므로 이 곳에서 런치패드를 Dock으로 끌어다 놓자.

그런다음 Application 폴더에서 런치패드에 추가하고 싶은 앱들을 하나씩 Dock에 있는 런치패드 아이콘으로 끌어다 놓으면 하나씩 하나씩 추가가 가능하다. Finder에서 응용프로그램 폴더를 들어가서 원하는 앱들을 모두 선택해서 끌어다 놓아도 되고, 유틸리티 폴더와 같이 폴더를 통째로 끌어다 놓아도 된다. 참고로 응용프로그램폴더가 아닌 곳에 설치된 앱도 런치패드 앱으로 아이콘을 끌어다 놓으면 런치패드에 등록되니 참고하라.

5. 정리

이제 마지막으로 등록된 앱의 아이콘을 정렬하고 정리해주면 된다.

팁 :  만약 런치패드 아이콘을 초기 상태로 복구하고 싶다면, Dock의 환경설정폴더에서 db 파일들을 모두 지워버리고 Dock을 재시작한 후 런치패드를 실행하면 응용프로그램 폴도를 자동으로 가져와서 모든 앱을 추가해준다.1 아니면 아까 백업해 둔 파일을 지금 DB 파일에 덮어써버려도 된다.

$rm ~/Library/Application\ Support/Dock/*.db

$killall Dock

  1. OSX 자체 그리고 대부분의 OSX용 앱들은 설정파일을 날려버리면 디폴트 값으로 자동으로 설정을 복구한다.

20111018 :: [OSX] Mail 앱에서 이름이 중복으로 들어가는 경우

이건 상당히 글로벌한(?) 문제인 것 같은데, OSX의 Mail 앱에서 (심지어는 최근에 업그레이드된 5.0에서) 나타나는 문제이다. 아마 이런 문제를 겪고 있는 사람이 꽤 될 것 같은데… 바로 주소록에서 ‘성’ 란을 빈칸으로 비워두고 이름란에 성을 붙여서 쓰는 경우에, 메일 작성 시 보내는 사람 주소를 자동완성으로 입력하면 이름이 중복되는 문제다.

예를 들어 ‘홍길동’이라는 이름이 주소록에 “홍” , “길동” (성, 이름) 으로 들어가 있지 않고 “”, “홍길동” 으로 이름에 3글자가 모두 들어 있는 경우, Mail 앱에서 홍길동에게 메일을 보내고 나면 “홍길동”, “홍길동”으로 이름이 바뀌어 있는 문제이다.

이는 상당히 고질적인데, 주소록에서 성 필드를 지우고 이름을 다시 “”, “홍길동”으로 수정해도 다시 한 번 메일을 보내면 이게 “홍길동”,”홍길동”으로 중복해서 수정되어 버린다. 아마 이 문제에 대한 리포트를 애플이 안 받진 않았을텐데… 버그인 건지 뭔지 도통 모르겠다. 아마 영어권에서는 성과 이름이 각각 분리되어 있으니 크게 불편을 못느끼는 것일 수도.

1. 자동 완성 기능을 사용하지 않는다. (Disable Auto Complete)

당연하게도 자동완성 기능을 사용하지 않으면 이런 문제를 겪지 않는다. 하지만 너무 불편하다. 친구에게 보내는 메일같은 경우에는 수신란에 메일 주소만 들어가도 상관 없지만 매번 “홍길동 <honggildong@mailmail.com>” 과 같은 식으로 주소를 넣어줄 수는 없는 일 아닌가. 따라서 Mail 앱을 잘 사용하지 않는 경우에만 이 방법을 추천한다.

 

2. 성 필드에 공백을 입력해 둔다. (Place white space into first name field)

이건 좀 꼼수인데, 성 필드에 공백 문자를 하나 입력해 두는 거다. 이러면 이 문제가 발생하지 않고 ” “,”홍길동”이 되어 일단 보이는데는 큰 문제가 없어 보일 수 있다. 대신에 이름 자동 완성 이후에 파란 타원 모양으로 처리되는 그래픽이 좀 밀려 보이는 문제는 있을 수 있겠다. 게다가 주소록이 큰 경우에 모든 사람의 성에 공백을 넣기란….

 

3. “이전 수신자” 목록을 지운다. (Clear Previous Receipts)

Mail 앱은 “이전 수신자” 목록을 사용하는데, 이게 주소록에 추가되지 않은 연락처를 관리하거나 자동 완성을 좀 더 빠르게 하는 목적으로 있는 것 같다. 문제는 이곳에 중복된 이름으로 이름이 들어 있는 경우에 주소록에 해당 메일 주소가 있으면 이 내용으로 업데이트 된다는 것. Mail의 윈도우 메뉴에서 이전 수신자를 클릭하여 열리는 목록의 전체를 지워버린다. 일단 이 부분이 정상적인 이름이 표시된다면 중복 이름은 표시되지 않는다.

4. “이전 수신자”를 아예 사용하지 않는다. (Disable Previous Receipts)

3번의 해결책이 완벽하지는 않다. 모종의 이유로 이전 수신자에 중복된 이름이 들어가버리는 경우가 생길 수 있는데, 이러면 똑같은 문제가 다시 발생할 수 있다. 따라서 아예 이전 수신자 기능 자체를 꺼두는 것도 (정신 건강에) 도움이 될 수 있다.

터미널을 열고 다음 명령을 입력한다.($ 는 입력하지 않는다. 그냥 터미널 프롬프트다)

$ defaults write com.apple.mail SuppressAddressHistory -bool YES

이 정도 해주면 좀 도움이 될 수 있을 것도 같다. 끝.