안녕하세요.
이번에는 Objective-C와 Swift에서 String 비교하는 방법에 대해 알아볼게요.
# NSString 비교 (for Objective-C)
NSString 비교 방법은 크게 2가지가 있습니다.
- ==
- [NSString isEqualToString:]
결론부터 말씀드리자면 문자열 자체를 비교할 때는 [NSString isEqualToString:] method를 사용해야 합니다.
이렇게요.
NSString *str1 = @"aaa";
NSString *str2 = @"aaa";
NSString *str3 = @"bbb";
NSLog(@"str1 and str2 are %@.", [str1 isEqualToString:str2] ? @"equal" : @"not equal");
NSLog(@"str1 and str3 are %@.", [str1 isEqualToString:str3] ? @"equal" : @"not equal");
// Result
// "str1 and str2 are equal."
// "str1 and str3 are not equal."
== 연산자는 서로의 주소값이 같은지 비교하는 연산자입니다.
그러니까 아래처럼 비교하면 문자열 자체는 같지만 서로 다른 값이라고 하겠...?
NSString *str1 = @"aaa";
NSString *str2 = @"aaa";
NSLog(@"str1 and str2 are %@.", str1 == str2 ? @"equal" : @"not equal"); 🤔
// Result
// "str1 and str2 are equal."
음????? 😨
주소값을 출력해볼게요.
NSString *str1 = @"aaa";
NSString *str2 = @"aaa";
NSLog(@"str1 and str2 are %@.", str1 == str2 ? @"equal" : @"not equal");
NSLog(@"str1 = %@, str1의 주소값 = %p, str1에 저장된 문자열의 주소값 = %p", str1, &str1, str1);
NSLog(@"str2 = %@, str2의 주소값 = %p, str2에 저장된 문자열의 주소값 = %p", str2, &str2, str2);
// Result
// str1 and str2 are equal.
// str1 = aaa, str1의 주소값 = 0x7ff7b4d61a78, str1에 저장된 문자열의 주소값 = 0x10b620b98
// str2 = aaa, str2의 주소값 = 0x7ff7b4d61a70, str2에 저장된 문자열의 주소값 = 0x10b620b98
아하. 이렇게 설정되어 있었군요.
즉, str1, str2에 저장된 문자열의 주소값이 같으니 == 연산자를 사용했을 때 동일하다고 판단하는 것 같아요.
공식 문서는 못 찾겠어서 추측해보자면...
컴파일러에서 통일한 타입의 통일한 값을 새로운 변수에 할당하는 경우 메모리에 새롭게 할당하지 않고 이미 존재하고 있는 데이터를 활용하는 것 같아요. 그러니 주소값이 같은 것이죠ㅎㅎ
그럼 이렇게 생각이 들 수 있어요.
그럼 == 연산자 사용하면 안됨?? 결국 문자열이 같은지 비교할 때 문제없는 거 아님?
하지만.. 이 생각은 버그가 발생할 수 있는 위험한 생각입니다.
아래 코드를 한번 볼까요?
NSString *str1 = @"aaa";
NSString *str2 = [NSMutableString stringWithString:@"aaa"];
NSLog(@"str1 and str2 are %@.", str1 == str2 ? @"equal" : @"not equal");
NSLog(@"str1 = %@, str1의 주소값 = %p, str1에 저장된 문자열의 주소값 = %p", str1, &str1, str1);
NSLog(@"str2 = %@, str2의 주소값 = %p, str2에 저장된 문자열의 주소값 = %p", str2, &str2, str2);
str1 하고 str2에 저장된 문자열은 @"aaa"로 동일합니다.
== 비교를 했을 때 같다고 나오면 좋겠지만 결과는...
// str1 and str2 are not equal.
// str1 = aaa, str1의 주소값 = 0x7ff7b4a46a78, str1에 저장된 문자열의 주소값 = 0x10b93bb98
// str2 = aaa, str2의 주소값 = 0x7ff7b4a46a70, str2에 저장된 문자열의 주소값 = 0x6000022d4c30
주소값이 다르게 설정되었어요. 왜 그럴까요??
주소값이 같게 설정되는 경우가 어떤 상황일 때라고 했죠?
컴파일러에서 통일한 타입의 통일한 값을 새로운 변수에 할당하는 경우
맞습니다. 통일한 타입 & 통일한 값 이어야 합니다.
현재 str1에 저장된 문자열은 NSString이지만 str2에 저장된 문자열은 NSMutableString 이기 때문에 서로 타입이 다르고,
그렇기 때문에 새로운 메모리를 할당받았고,
그렇기 때문에 == 연산을 했을 때 서로 다르다고 판단하는 것이죠.
뭐... 이런저런 이유 때문에라도 NSString 비교할 때는 == 연산자 대신 [NSString isEqualToString:] method를 사용해주시는게 좋을 것 같습니다ㅎㅎ
# String 비교 (for Swift)
Swift에서 String은 구조체이고 value type 입니다.
그래서 단순히 == 연산자를 사용해서 문자열 비교가 가능합니다.
var str1 = "aaa"
var str2 = "aaa"
print("\(str1 == str2)") // true
추가로.. Swift에서는 reference 비교를 위해 === 연산자가 있길래 String 타입에도 사용해보려고 했는데요.
=== 연산자는 reference type 끼리만 사용이 가능하기 때문에 String 타입은 === 연산자를 사용할 수 없었습니다..허헣
var str1 = "aaa"
var str2 = "aaa"
print("\(str1 === str2)") // Argument type 'String' expected to be an instance of a class or class-constrained type
## 참고
- https://developer.apple.com/documentation/foundation/nsstring
- https://docs.swift.org/swift-book/LanguageGuide/StringsAndCharacters.html
- https://docs.swift.org/swift-book/LanguageGuide/BasicOperators.html#ID70
- https://docs.swift.org/swift-book/LanguageGuide/ClassesAndStructures.html#ID91
언어마다 String 비교 방식은 서로 다르고 매우 중요한 부분이기 때문에, 특정 언어를 사용할 때는 꼭 특징을 파악해서 사용하는게 좋을 것 같아요.
(물론 모두 외울 필요는 없겠지만요ㅎㅎ)
이번 글은 여기서 마무리.
'iOS' 카테고리의 다른 글
Moya async API 추가하기 (0) | 2023.04.11 |
---|---|
앱 이름 현지화(localization)하는 방법 (2) | 2023.03.09 |
Apple Common Scheme List (0) | 2022.08.04 |
Private Pod 배포 방법 (0) | 2022.06.01 |
SwiftUI <-> UIKit 이벤트 전달 방법 (0) | 2022.05.21 |