어쨌든 [NSString stringWithFormat:@"%p", myVar]
Objective-C에서 새로운 Swift 언어로 를 시뮬레이션 할 수 있습니까?
예를 들면 다음과 같습니다.
let str = "A String"
println(" str value \(str) has address: ?")
답변
스위프트 2
이것은 이제 표준 라이브러리의 일부입니다 unsafeAddressOf
.
/// Return an UnsafePointer to the storage used for `object`. There's
/// not much you can do with this other than use it to identify the
/// object
스위프트 3
스위프트 3의 경우 다음을 사용하십시오 withUnsafePointer
.
var str = "A String"
withUnsafePointer(to: &str) {
print(" str value \(str) has address: \($0)")
}
답변
참고 : 이것은 참조 유형입니다.
스위프트 4/5 :
print(Unmanaged.passUnretained(someVar).toOpaque())
someVar의 메모리 주소를 인쇄합니다. (@Ying 덕분에)
스위프트 3.1 :
print(Unmanaged<AnyObject>.passUnretained(someVar as AnyObject).toOpaque())
someVar의 메모리 주소를 인쇄합니다.
답변
이 답변은 상당히 오래되었습니다. 설명하는 많은 방법이 더 이상 작동하지 않습니다. 특히 .core
더 이상 액세스 할 수 없습니다.
그러나 @drew의 대답은 정확하고 간단합니다.
이제는 표준 라이브러리 인 unsafeAddressOf의 일부입니다.
따라서 귀하의 질문에 대한 답변은 다음과 같습니다.
println(" str value \(str) has address: \(unsafeAddressOf(str))")
다음은 정답으로 표시된 원래 답변입니다 (후손 / 정치).
스위프트는 “숨김”포인터를 가리지 만 여전히 후드 아래에 존재합니다. (런타임이 필요하기 때문에 Objc 및 C와의 호환성 이유로)
그러나 알아야 할 것이 없지만 먼저 Swift String의 메모리 주소를 인쇄하는 방법은 무엇입니까?
var aString : String = "THIS IS A STRING"
NSLog("%p", aString.core._baseAddress) // _baseAddress is a COpaquePointer
// example printed address 0x100006db0
이것은 문자열의 메모리 주소를 인쇄합니다. XCode-> 디버그 워크 플로-> 메모리보기를 열고 인쇄 된 주소로 이동하면 문자열의 원시 데이터가 표시됩니다. 이것은 문자열 리터럴이므로 이진 저장소 (스택 또는 힙이 아님) 내의 메모리 주소입니다.
그러나 당신이 할 경우
var aString : String = "THIS IS A STRING" + "This is another String"
NSLog("%p", aString.core._baseAddress)
// example printed address 0x103f30020
문자열은 런타임에 생성되므로 스택에 있습니다.
참고 : .core._baseAddress는 문서화되어 있지 않으며 변수 관리자에서 찾고 있으며 나중에 숨길 수 있습니다.
_baseAddress가 모든 유형에서 사용 가능한 것은 아닙니다. 여기 CInt가있는 다른 예
var testNumber : CInt = 289
takesInt(&testNumber)
takesInt
이런 C 도우미 기능은 어디에 있습니까?
void takesInt(int *intptr)
{
printf("%p", intptr);
}
Swift 측에서이 함수는입니다 takesInt(intptr: CMutablePointer<CInt>)
. 따라서 CMutablePointer를 CInt로 가져 가면 & varname으로이를 얻을 수 있습니다.
함수 인쇄 0x7fff5fbfed98
이 메모리 주소, 당신은 289 (16 진수 표기) 찾을 수 있습니다. 당신은 그것으로 내용을 변경할 수 있습니다*intptr = 123456
이제 알아야 할 다른 것들이 있습니다.
즉, 문자열은 객체가 아닌 기본 유형입니다.
CInt는 C int 유형에 매핑 된 Swift 유형입니다.
객체의 메모리 주소를 원한다면 다른 것을해야합니다.
Swift에는 C와 상호 작용할 때 사용할 수있는 몇 가지 포인터 유형이 있으며 여기에서 읽을 수 있습니다. Swift 포인터 유형
또한, 선언을 탐색하는 방법에 대한 자세한 내용을 이해할 수 있습니다 (cmd + 유형 클릭). 다른 유형의 포인터
var aString : NSString = "This is a string" // create an NSString
var anUnmanaged = Unmanaged<NSString>.passUnretained(aString) // take an unmanaged pointer
var opaque : COpaquePointer = anUnmanaged.toOpaque() // convert it to a COpaquePointer
var mut : CMutablePointer = &opaque // this is a CMutablePointer<COpaquePointer>
printptr(mut) // pass the pointer to an helper function written in C
printptr
이 구현으로 내가 만든 C 도우미 함수입니다.
void printptr(void ** ptr)
{
printf("%p", *ptr);
}
다시 한 번, 주소의 예가 인쇄되었습니다. 0x6000000530b0
메모리 검사기를 통과하면 NSString을 찾을 수 있습니다.
Swift에서 포인터로 할 수있는 한 가지 작업 (입력 매개 변수로 수행 할 수도 있음)
func playWithPointer (stringa :AutoreleasingUnsafePointer<NSString>)
{
stringa.memory = "String Updated";
}
var testString : NSString = "test string"
println(testString)
playWithPointer(&testString)
println(testString)
또는 Objc / c와 상호 작용
// objc side
+ (void)writeString:(void **)var
{
NSMutableString *aString = [[NSMutableString alloc] initWithFormat:@"pippo %@", @"pluto"];
*var = (void *)CFBridgingRetain(aString); // Retain!
}
// swift side
var opaque = COpaquePointer.null() // create a new opaque pointer pointing to null
TestClass.writeString(&opaque)
var string = Unmanaged<NSString>.fromOpaque(opaque).takeRetainedValue()
println(string)
// this prints pippo pluto
답변
객체의 (힙) 주소를 얻으려면
func address<T: AnyObject>(o: T) -> Int {
return unsafeBitCast(o, Int.self)
}
class Test {}
var o = Test()
println(NSString(format: "%p", address(o))) // -> 0x7fd5c8700970
( 편집 : Swift 1.2에는 이제라는 유사한 기능이 포함되어 unsafeAddressOf
있습니다.)
Objective-C에서 이것은 다음과 같습니다 [NSString stringWithFormat:@"%p", o]
.
o
인스턴스에 대한 참조입니다. 따라서 o
다른 변수에 할당 된 경우 o2
반환되는 주소 o2
는 동일합니다.
구조체 ( String
) 및 기본 유형 ( Int
)은 스택에 직접 존재하므로 구조체에는 적용되지 않습니다 . 그러나 스택에서 위치를 검색 할 수 있습니다.
구조체, 빌드 타입 또는 객체 참조의 (스택) 주소를 얻으려면
func address(o: UnsafePointer<Void>) -> Int {
return unsafeBitCast(o, Int.self)
}
println(NSString(format: "%p", address(&o))) // -> 0x10de02ce0
var s = "A String"
println(NSString(format: "%p", address(&s))) // -> 0x10de02ce8
var i = 55
println(NSString(format: "%p", address(&i))) // -> 0x10de02d00
Objective-C에서 이것은 [NSString stringWithFormat:@"%p", &o]
또는 [NSString stringWithFormat:@"%p", &i]
입니다.
s
구조체입니다. 따라서 s
다른 변수에 할당 된 경우 s2
값이 복사되고 반환 된 주소 s2
가 달라집니다.
함께 맞추는 방법 (포인터 요약)
Objective-C에서와 같이와 관련된 두 개의 다른 주소가 o
있습니다. 첫 번째는 객체의 위치이고, 두 번째는 객체에 대한 참조 (또는 포인터)의 위치입니다.
예, 이것은 디버거가 우리에게 말할 수있는 주소 0x7fff5fbfe658의 내용이 숫자 0x6100000011d0임을 의미합니다.
(lldb) x/g 0x7fff5fbfe658
0x7fff5fbfe658: 0x00006100000011d0
따라서 문자열이 구조체 인 것을 제외하고는 내부적 으로이 모든 것이 (Objective-) C와 동일하게 작동합니다.
(Xcode 6.3 현재)
답변
TL; DR
struct MemoryAddress<T>: CustomStringConvertible {
let intValue: Int
var description: String {
let length = 2 + 2 * MemoryLayout<UnsafeRawPointer>.size
return String(format: "%0\(length)p", intValue)
}
// for structures
init(of structPointer: UnsafePointer<T>) {
intValue = Int(bitPattern: structPointer)
}
}
extension MemoryAddress where T: AnyObject {
// for classes
init(of classInstance: T) {
intValue = unsafeBitCast(classInstance, to: Int.self)
// or Int(bitPattern: Unmanaged<T>.passUnretained(classInstance).toOpaque())
}
}
/* Testing */
class MyClass { let foo = 42 }
var classInstance = MyClass()
let classInstanceAddress = MemoryAddress(of: classInstance) // and not &classInstance
print(String(format: "%018p", classInstanceAddress.intValue))
print(classInstanceAddress)
struct MyStruct { let foo = 1 } // using empty struct gives weird results (see comments)
var structInstance = MyStruct()
let structInstanceAddress = MemoryAddress(of: &structInstance)
print(String(format: "%018p", structInstanceAddress.intValue))
print(structInstanceAddress)
/* output
0x0000000101009b40
0x0000000101009b40
0x00000001005e3000
0x00000001005e3000
*/
( 요점 )
Swift에서는 값 유형 (구조) 또는 참조 유형 (클래스)을 처리합니다. 할 때 :
let n = 42 // Int is a structure, i.e. value type
일부 메모리는 주소 X에 할당되며이 주소에서 값 42를 찾을 수 있습니다. 그렇게하면 &n
주소 X를 가리키는 포인터가 생성되므로 위치를 &n
알려줍니다 n
.
(lldb) frame variable -L n
0x00000001005e2e08: (Int) n = 42
(lldb) memory read -c 8 0x00000001005e2e08
0x1005e2e08: 2a 00 00 00 00 00 00 00 // 0x2a is 42
할 때 :
class C { var foo = 42, bar = 84 }
var c = C()
메모리는 두 곳에 할당됩니다 :
- 클래스 인스턴스 데이터가있는 주소 Y에서
- 클래스 인스턴스 참조가있는 주소 X에서
앞에서 말했듯이 클래스는 참조 유형입니다. 따라서 값은 c
주소 X에 있으며 여기서 Y 값을 찾을 수 있습니다. 주소 Y + 16 foo
에서는 주소 Y + 24에서 찾을 수 있습니다 bar
( + 0과 + 8에서 유형 데이터와 참조 횟수를 찾을 수 있습니다. 이에 대해 더 자세히 말할 수는 없습니다 …).
(lldb) frame variable c // gives us address Y
(testmem.C) c = 0x0000000101a08f90 (foo = 42, bar = 84)
(lldb) memory read 0x0000000101a08f90 // reading memory at address Y
0x101a08f90: e0 65 5b 00 01 00 00 00 02 00 00 00 00 00 00 00
0x101a08fa0: 2a 00 00 00 00 00 00 00 54 00 00 00 00 00 00 00
0x2a
42 (foo)이고 0x54
84 (bar)입니다.
두 경우 모두, 사용 &n
또는 것은 &c
우리가 원하는하지만 참조 유형 아니라고, 값 유형의 우리에게 주소 X를 줄 것이다.
할 때 :
let referencePointer = UnsafeMutablePointer<C>(&c)
참조에 포인터, 즉 X 주소를 가리키는 포인터를 withUnsafePointer(&c) {}
만듭니다.를 사용할 때도 마찬가지 입니다.
(lldb) frame variable referencePointer
(UnsafeMutablePointer<testmem.C>) referencePointer = 0x00000001005e2e00 // address X
(lldb) memory read -c 8 0x00000001005e2e00 // read memory at address X
0x1005e2e00: 20 ec 92 01 01 00 00 00 // contains address Y, consistent with result below:
(lldb) frame variable c
(testmem.C) c = 0x000000010192ec20 (foo = 42, bar = 84)
이제 우리는 후드 아래에서 일어나는 일에 대해 더 잘 이해했으며 이제 주소 X에서 주소 Y (원하는 주소)를 찾을 수 있습니다.이를 얻기 위해 다음을 수행 할 수 있습니다.
let addressY = unsafeBitCast(c, to: Int.self)
확인 중 :
(lldb) frame variable addressY -f hex
(Int) addressY = 0x0000000101b2fd20
(lldb) frame variable c
(testmem.C) c = 0x0000000101b2fd20 (foo = 42, bar = 84)
이를 수행하는 다른 방법이 있습니다.
let addressY1 = Int(bitPattern: Unmanaged.passUnretained(c).toOpaque())
let addressY2 = withUnsafeMutableBytes(of: &c) { $0.load(as: Int.self) }
toOpaque()
실제로 호출합니다 unsafeBitCast(c, to: UnsafeMutableRawPointer.self)
.
나는 이것이 도움이 되었기를 바란다.
답변
참조 유형 :
- ID를 나타내는 참조 유형의 메모리 주소를 얻는 것이 좋습니다.
===
identity 연산자는 2 개의 객체가 동일한 참조를 가리키는 지 확인하는 데 사용됩니다.ObjectIdentifier
메모리 주소를 얻는 데 사용
암호:
class C {}
let c1 = C()
let c2 = c1
//Option 1:
print("c1 address: \(Unmanaged.passUnretained(c1).toOpaque())")
//Option 2:
let o1 = ObjectIdentifier(c1)
let o2 = ObjectIdentifier(c2)
print("o1 -> c1 = \(o1)")
print("o2 -> c2 = \(o2)")
if o1 == o2 {
print("c1 = c2")
} else {
print("c1 != c2")
}
//Output:
//c1 address: 0x000060c000005b10
//o1 -> c1 = ObjectIdentifier(0x000060c000005b10)
//o2 -> c2 = ObjectIdentifier(0x000060c000005b10)
//c1 = c2
가치 유형 :
- 값 유형의 메모리 주소를 가져와야하는 것은 그다지 중요하지 않으며 (값이므로) 값의 동등성에 더 중점을 둡니다.
답변
이것을 사용하십시오 :
print(String(format: "%p", object))