어쨌든 [NSString stringWithFormat:@"%p", myVar]
Objective-C에서 새로운 Swift 언어로 를 시뮬레이션 할 수 있습니까?
예를 들면 다음과 같습니다.
let str = "A String"
println(" str value \(str) has address: ?")
어쨌든 [NSString stringWithFormat:@"%p", myVar]
Objective-C에서 새로운 Swift 언어로 를 시뮬레이션 할 수 있습니까?
예를 들면 다음과 같습니다.
let str = "A String"
println(" str value \(str) has address: ?")
답변:
이것은 이제 표준 라이브러리의 일부입니다 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의 경우 다음을 사용하십시오 withUnsafePointer
.
var str = "A String"
withUnsafePointer(to: &str) {
print(" str value \(str) has address: \($0)")
}
withUnsafePointer
결과 cannot pass immutable value as inout argument
오류가 발생했습니다.
print(self.description)
prints <MyViewController: 0x101c1d580>
, 우리는 그것을 참조로 사용합니다. 주소가 다른 var mutableSelf = self; withUnsafePointer(to: &mutableSelf) { print(String(format: "%p", $0)) }
인쇄물 0x16fde4028
. 아무도 이유를 설명 할 수 있습니까?
0x101c1d580
예상대로 :print(String(format: "%p", unsafeBitCast(self, to: Int.self)))
UnsafePointer
구조체입니다. 그래서 주소 를 인쇄 하려면 (구조 자체가 아닌) 주소 를 인쇄하려면 인쇄해야합니다 String(format: "%p", $0.pointee)
!
참고 : 이것은 참조 유형입니다.
print(Unmanaged.passUnretained(someVar).toOpaque())
someVar의 메모리 주소를 인쇄합니다. (@Ying 덕분에)
print(Unmanaged<AnyObject>.passUnretained(someVar as AnyObject).toOpaque())
someVar의 메모리 주소를 인쇄합니다.
print(Unmanaged<AnyObject>.passUnretained(someVar as AnyObject).toOpaque())
Unmanaged
과 같이 사용할 수 있습니다 print(Unmanaged<AnyObject>.fromOpaque(&myStruct).toOpaque())
.
Unmanaged.passUnretained(someVar).toOpaque()
(일반 사양 필요 없음)
debugDescription
끝에 추가 하는 것이 좋습니다 .
이 답변은 상당히 오래되었습니다. 설명하는 많은 방법이 더 이상 작동하지 않습니다. 특히 .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()
메모리는 두 곳에 할당됩니다 :
앞에서 말했듯이 클래스는 참조 유형입니다. 따라서 값은 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)
.
나는 이것이 도움이 되었기를 바란다.
MemoryLocation
하면 2 개의 다른 주소 가 생성됩니다.
===
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))
MyClass?
"이 CVarArg를 준수하지 않는다는 컴파일러 불만 이 표시되면 할 수 있습니다 extension Optional : CVarArg { }
. 그렇지 않으면 이것은 다른 답변의 모든 "안전하지 않은"광기없이 주소를 인쇄하는 것으로 보입니다.
var _cVarArgEncoding: [Int]
on 구현이 필요합니다 CVarArg
. 어떻게 구현해야하는지 명확하지 않습니다.
디버거에서 이것을보고 다른 작업을 수행하지 않으려면 실제로 Int
포인터를 가져올 필요가 없습니다 . 메모리에서 객체 주소의 문자열 표현을 얻으려면 다음과 같이 사용하십시오.
public extension NSObject { // Extension syntax is cleaner for my use. If your needs stem outside NSObject, you may change the extension's target or place the logic in a global function
public var pointerString: String {
return String(format: "%p", self)
}
}
사용법 예 :
print(self.pointerString, "Doing something...")
// Prints like: 0x7fd190d0f270 Doing something...
또한 객체 를 재정의하지 않고 간단히 객체를 인쇄 할 수 있으며description
더 설명적인 텍스트와 함께 포인터 주소를 표시합니다.
print(self, "Doing something else...")
// Prints like: <MyModule.MyClass: 0x7fd190d0f270> Doing something else...
// Sometimes like: <_TtCC14__lldb_expr_668MyModule7MyClass: 0x7fd190d0f270> Doing something else...
extension String {
static func pointer(_ object: AnyObject?) -> String {
guard let object = object else { return "nil" }
let opaque: UnsafeMutableRawPointer = Unmanaged.passUnretained(object).toOpaque()
return String(describing: opaque)
}
}
print("FileManager.default: \(String.pointer(FileManager.default))")
// FileManager.default: 0x00007fff5c287698
print("nil: \(String.pointer(nil))")
// nil: nil
Unmanaged.passUnretained(myObject).toOpaque()
대신 제대로 작동합니다.
AnyObject
매개 변수 가 필요합니다 . Any
입력 유형으로 선호 합니다.
let array1 = [1,2,3]
let array2 = array1
array1.withUnsafeBufferPointer { (point) in
print(point) // UnsafeBufferPointer(start: 0x00006000004681e0, count: 3)
}
array2.withUnsafeBufferPointer { (point) in
print(point) // UnsafeBufferPointer(start: 0x00006000004681e0, count: 3)
}
self?.array
.
@Drew가 제공하는 답변은 클래스 유형에만 사용할 수 있습니다.
@nschum이 제공하는 답변은 구조체 유형에 대해서만 가능합니다.
그러나 두 번째 방법을 사용하여 값 유형 요소가있는 배열의 주소를 얻는 경우. Swift에서 Swift 어레이는 쓰기 중 복사이므로 C / C ++에 제어권을 넘기면 Swift가 이러한 방식으로 동작하는지 확인할 수 없습니다 ( &
주소를 가져 오기 위해 사용 하는 경우). 첫 번째 방법을 대신 사용하면 자동으로 원하지 않는 것으로 변환 Array
됩니다 NSArray
.
내가 찾은 가장 간단하고 통일 된 방법은 lldb 명령을 사용하는 것 frame variable -L yourVariableName
입니다.
또는 당신은 그들의 답변을 결합 할 수 있습니다 :
func address(o: UnsafePointer<Void>) {
let addr = unsafeBitCast(o, Int.self)
print(NSString(format: "%p", addr))
}
func address<T: AnyObject>(o: T) -> String{
let addr = unsafeBitCast(o, Int.self)
return NSString(format: "%p", addr) as String
}
이것은 스위프트 3입니다.
@CharlieMonroe와 같이 주소를 정수로 얻고 싶습니다. 특히 스레드 이름을 사용할 수없는 상황에서 진단 로깅 모듈에서 스레드 ID로 사용할 Thread 개체의 주소를 원했습니다.
Charlie Monroe의 코드를 기반으로 지금까지 내가 생각해 낸 내용은 다음과 같습니다. 그러나 Swift를 처음 접하는 사람이라면 조심하십시오.
// Convert the memory address of the current Thread object into an Int for use as a thread ID
let objPtr = Unmanaged.passUnretained(Thread.current).toOpaque()
let onePtr = UnsafeMutableRawPointer(bitPattern: 1)! // 1 used instead of 0 to avoid crash
let rawAddress : Int64 = onePtr.distance(to: objPtr) + 1 // This may include some high-order bits
let address = rawAddress % (256 * 1024 * 1024 * 1024) // Remove high-order bits
마지막 문장은 0x60000007DB3F와 같은 주소를 얻지 못했기 때문입니다. 마지막 명령문의 모듈로 연산은이를 0x7DB3F로 변환합니다.
이것은 가장 빠르거나 안전한 방법이 아닙니다. 그러나 그것은 나를 위해 작동합니다. 그러면 nsobject 하위 클래스가이 속성을 채택 할 수 있습니다.
public extension NSObject {
public var memoryAddress : String? {
let str = "\(self.self)".components(separatedBy: ": ")
guard str.count > 1 else { return nil }
return str[1].replacingOccurrences(of: ">", with: "")
}
}
//usage
let foo : String! = "hello"
Swift.print(foo.memoryAddress) // prints 0x100f12980
[NSString stringWithFormat:@"%p", myVar]
,myVar
포인터이어야합니다. Swift 코드에서str
포인터가 아닙니다. 따라서 비교는 적용되지 않습니다.