In một địa chỉ bộ nhớ thay đổi nhanh chóng


165

Có cách nào để mô phỏng [NSString stringWithFormat:@"%p", myVar], từ Objective-C, trong ngôn ngữ Swift mới không?

Ví dụ:

let str = "A String"
println(" str value \(str) has address: ?")

2
Trong [NSString stringWithFormat:@"%p", myVar], myVarphải là một con trỏ. Trong mã Swift của bạn, strkhông phải là một con trỏ. Vì vậy, so sánh không áp dụng.
user102008

5
Điều đáng chú ý là, ít nhất là khi tôi gõ cái này, hai nhận xét trên là không chính xác.
Ben Leggiero

Câu trả lời:


112

Swift 2

Đây là một phần của thư viện chuẩn : 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

Swift 3

Đối với Swift 3, sử dụng withUnsafePointer:

var str = "A String"
withUnsafePointer(to: &str) {
    print(" str value \(str) has address: \($0)")
}

2
unsafeAddressOf () chỉ hoạt động cho các loại lớp (như @Nick chỉ ra bên dưới). Do đó, câu trả lời này chỉ hoạt động nếu Foundation được nhập và String được bắc cầu đến NSString. Trong Swift đơn giản, String là một loại giá trị và unsafeAddressOf không thể được sử dụng để lấy địa chỉ của nó (nỗ lực dẫn đến lỗi biên dịch).
Stephen Schaub

29
Nếu tôi muốn in địa chỉ có giá trị bất biến với Swift 3 thì sao? withUnsafePointerdẫn đến cannot pass immutable value as inout argumentlỗi.
Alexander Vasenin

12
Mặc dù câu trả lời được chấp nhận và bình chọn cao nhất, nó vẫn cho kết quả sai . Ví dụ: print(self.description)bản in <MyViewController: 0x101c1d580>, chúng tôi sử dụng nó như một tài liệu tham khảo. var mutableSelf = self; withUnsafePointer(to: &mutableSelf) { print(String(format: "%p", $0)) }in 0x16fde4028rõ ràng là địa chỉ khác nhau. Ai có thể giải thích tại sao?
Alexander Vasenin

4
BTW, bản in này 0x101c1d580như mong đợi:print(String(format: "%p", unsafeBitCast(self, to: Int.self)))
Alexander Vasenin

8
@nyg Câu trả lời của bạn đã cho tôi manh mối về nguyên nhân lỗi thực tế: UnsafePointerlà một cấu trúc, vì vậy để in địa chỉ mà nó trỏ đến (chứ không phải chính cấu trúc), bạn phải in String(format: "%p", $0.pointee)!
Alexander Vasenin

213

Lưu ý: Đây là loại tham khảo.

Swift 4/5:

print(Unmanaged.passUnretained(someVar).toOpaque())

In địa chỉ bộ nhớ của someVar. (cảm ơn @Ying)


Swift 3,1:

print(Unmanaged<AnyObject>.passUnretained(someVar as AnyObject).toOpaque())

In địa chỉ bộ nhớ của someVar.



2
Xcode 8.2.1 tự động sửa lỗi đang nói với tôi rằng đó là bây giờprint(Unmanaged<AnyObject>.passUnretained(someVar as AnyObject).toOpaque())
Jeff

2
Điều này sẽ không đúng chỉ khi someVar là một đối tượng. Nếu someVar tình cờ là một loại giá trị như struct, điều này sẽ cung cấp một địa chỉ khác nhau mỗi khi nó được thực thi.
OutOnAWeekend

3
@OutOnAWeekend Bạn nói đúng, rất có thể là do cấu trúc được sao chép khi được truyền dưới dạng đối số. Sử dụng Unmanagednó có thể được thực hiện như thế này : print(Unmanaged<AnyObject>.fromOpaque(&myStruct).toOpaque()).
nyg

1
Kể từ Swift 4, tôi cũng có thể in câu thần chú này - Unmanaged.passUnretained(someVar).toOpaque()(không cần thông số chung)
Ying

2
Câu trả lời Swift 4 là hoàn hảo. Nếu bạn cũng muốn có được đại diện chuỗi mà không in, tôi khuyên bạn nên thêm debugDescriptionvào cuối của chuỗi.
Patrick

51

Lưu ý rằng câu trả lời này đã khá cũ. Nhiều phương pháp mà nó mô tả không còn hoạt động. Cụ .corethể không thể truy cập được nữa.

Tuy nhiên, câu trả lời của @ drew là chính xác và đơn giản:

Đây hiện là một phần của thư viện chuẩn: unsafeAddressOf.

Vì vậy, câu trả lời cho câu hỏi của bạn là:

println(" str value \(str) has address: \(unsafeAddressOf(str))")

Đây là câu trả lời ban đầu được đánh dấu đúng (cho hậu thế / phép lịch sự):

Swift "ẩn" con trỏ, nhưng chúng vẫn tồn tại dưới mui xe. (vì thời gian chạy cần nó và vì lý do tương thích với Objc và C)

Tuy nhiên, có vài điều cần biết, nhưng trước tiên làm thế nào để in địa chỉ bộ nhớ của Chuỗi Swift?

    var aString : String = "THIS IS A STRING"
    NSLog("%p", aString.core._baseAddress)  // _baseAddress is a COpaquePointer
   // example printed address 0x100006db0

Thao tác này sẽ in địa chỉ bộ nhớ của chuỗi, nếu bạn mở XCode -> Luồng công việc gỡ lỗi -> Xem bộ nhớ và đi đến địa chỉ được in, bạn sẽ thấy dữ liệu thô của chuỗi. Vì đây là một chuỗi ký tự, đây là một địa chỉ bộ nhớ trong bộ lưu trữ nhị phân (không phải stack hoặc heap).

Tuy nhiên, nếu bạn làm

    var aString : String = "THIS IS A STRING" + "This is another String"
    NSLog("%p", aString.core._baseAddress)

    // example printed address 0x103f30020

Điều này sẽ nằm trên ngăn xếp, bởi vì chuỗi được tạo khi chạy

LƯU Ý: .core._baseAddress không được ghi lại, tôi thấy nó đang tìm kiếm trong trình kiểm tra biến và nó có thể bị ẩn trong tương lai

_baseAddress không có sẵn trên tất cả các loại, ở đây một ví dụ khác với CInt

    var testNumber : CInt = 289
    takesInt(&testNumber)

Trong trường hợp takesIntlà một hàm C helper như thế này

void takesInt(int *intptr)
{
    printf("%p", intptr);
}

Về phía Swift, chức năng này là takesInt(intptr: CMutablePointer<CInt>), do đó, nó cần một CMutablePulum tới CInt và bạn có thể có được nó với & varname

Hàm in 0x7fff5fbfed98, một địa chỉ bộ nhớ này bạn sẽ tìm thấy 289 (theo ký hiệu thập lục phân). Bạn có thể thay đổi nội dung của nó với*intptr = 123456

Bây giờ, một số điều khác để biết.

Chuỗi, trong swift, là một kiểu nguyên thủy, không phải là một đối tượng.
CInt là một loại Swift được ánh xạ tới C int Type.
Nếu bạn muốn địa chỉ bộ nhớ của một đối tượng, bạn phải làm một cái gì đó khác nhau.
Swift có một số Loại Con trỏ có thể được sử dụng khi tương tác với C và bạn có thể đọc về chúng tại đây: Các loại Con trỏ Swift
Ngoài ra, bạn có thể hiểu thêm về chúng khám phá khai báo của chúng (cmd + nhấp vào loại), để hiểu cách chuyển đổi một loại con trỏ vào một cái khác

    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 là một hàm trợ giúp C tôi đã tạo, với cách thực hiện này

void printptr(void ** ptr)
{
    printf("%p", *ptr);
}

Một lần nữa, một ví dụ về địa chỉ được in: 0x6000000530b0và nếu bạn đi qua trình kiểm tra bộ nhớ, bạn sẽ tìm thấy NSString của mình

Một điều bạn có thể làm với các con trỏ trong Swift (điều này thậm chí có thể được thực hiện với các tham số đầu vào)

    func playWithPointer (stringa :AutoreleasingUnsafePointer<NSString>) 
    {
        stringa.memory = "String Updated";
    }

    var testString : NSString = "test string"
    println(testString)
    playWithPointer(&testString)
    println(testString)

Hoặc, tương tác với 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

có, con trỏ phải thoát nhưng không chỉ vì lý do tương thích khi bạn giới thiệu. các con trỏ thường được sử dụng bởi hệ điều hành. ngay cả khi ngôn ngữ là ngôn ngữ cấp cao, con trỏ phải tồn tại trong bất kỳ ngôn ngữ nào vào bất kỳ lúc nào trong công cụ của hệ điều hành.
holex

Tôi đã nói "vì lý do tương thích VÀ vì thời gian chạy cần nó" :-) câu lệnh thứ hai nhắc lại những gì bạn đang nói (Tôi cho rằng một lập trình viên biết và hiểu nó, vì vậy tôi đã dành vài từ)
OliveraX

Tôi cho rằng điều này không áp dụng nữa?
aleclarson

Đúng. Tôi đã chỉnh sửa câu trả lời đúng từ @Drew vào nó.
Rog

@LombaX chúng ta chỉ có thể in địa chỉ của loại tham chiếu? Tôi không thể in địa chỉ của các biến?
AbhimanyuAryan

21

Để lấy địa chỉ (heap) của một đối tượng

func address<T: AnyObject>(o: T) -> Int {
    return unsafeBitCast(o, Int.self)
}

class Test {}
var o = Test()
println(NSString(format: "%p", address(o))) // -> 0x7fd5c8700970

( Chỉnh sửa: Swift 1.2 hiện bao gồm một chức năng tương tự được gọi là unsafeAddressOf.)

Trong Mục tiêu-C, điều này sẽ là [NSString stringWithFormat:@"%p", o].

olà một tham chiếu đến ví dụ. Vì vậy, nếu ođược gán cho một biến khác o2, địa chỉ được trả về o2sẽ giống nhau.

Điều này không áp dụng cho các cấu trúc (bao gồm String) và các kiểu nguyên thủy (như Int), vì các kiểu này sống trực tiếp trên ngăn xếp. Nhưng chúng ta có thể lấy vị trí trên stack.

Để lấy địa chỉ (ngăn xếp) của cấu trúc, kiểu dựng sẵn hoặc tham chiếu đối tượng

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

Trong Mục tiêu-C, điều này sẽ là [NSString stringWithFormat:@"%p", &o]hoặc [NSString stringWithFormat:@"%p", &i].

slà cấu trúc. Vì vậy, nếu sđược gán cho một biến khác s2, giá trị sẽ được sao chép và địa chỉ được trả về s2sẽ khác.

Làm thế nào nó phù hợp với nhau (tóm tắt con trỏ)

Giống như trong Objective-C, có hai địa chỉ khác nhau được liên kết với o. Đầu tiên là vị trí của đối tượng, thứ hai là vị trí của tham chiếu (hoặc con trỏ) đến đối tượng.

Có, điều này có nghĩa là nội dung của địa chỉ 0x7fff5fbfe658 là số 0x6100000011d0 như trình gỡ lỗi có thể cho chúng tôi biết:

(lldb) x/g 0x7fff5fbfe658
0x7fff5fbfe658: 0x00006100000011d0

Vì vậy, ngoại trừ các chuỗi là cấu trúc, bên trong tất cả các công việc này khá giống như trong (Mục tiêu-) C.

(Hiện tại kể từ Xcode 6.3)


Hừm. Lấy địa chỉ ngăn xếp của tài sản của một đối tượng không nhất quán. Có ý kiến ​​gì không? Kiểm tra ý chính này!
aleclarson

Các thuộc tính của đối tượng nằm trên heap, không phải stack. Khi bạn chuyển thuộc tính của một thể hiện của lớp dưới dạng UnsafePulum, Swift thực sự sao chép giá trị trước và bạn nhận được địa chỉ của bản sao. Tôi nghi ngờ đó là để ngăn chặn mã C phá vỡ giao diện của đối tượng và gây ra trạng thái không nhất quán. Tôi không biết có cách nào khác không.
nschum


20

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
*/

( Ý chính )


Trong Swift, chúng ta xử lý các loại giá trị (cấu trúc) hoặc loại tham chiếu (lớp). Khi làm:

let n = 42 // Int is a structure, i.e. value type

Một số bộ nhớ được phân bổ tại địa chỉ X và tại địa chỉ này, chúng ta sẽ tìm thấy giá trị 42. Việc &ntạo một con trỏ trỏ đến địa chỉ X, do đó &ncho chúng ta biết nvị trí của 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

Khi làm:

class C { var foo = 42, bar = 84 }
var c = C()

Bộ nhớ được phân bổ ở hai nơi:

  • tại địa chỉ Y nơi chứa dữ liệu cá thể của lớp và
  • tại địa chỉ X nơi tham chiếu thể hiện của lớp.

Như đã nói, các lớp là các loại tham chiếu: vì vậy giá trị của cđược đặt tại địa chỉ X, tại đó chúng ta sẽ tìm thấy giá trị của Y. Và tại địa chỉ Y + 16 chúng ta sẽ tìm thấy foovà tại địa chỉ Y + 24 chúng ta sẽ tìm thấy bar( tại + 0 và + 8 chúng tôi sẽ tìm thấy dữ liệu loại và số tham chiếu, tôi không thể nói cho bạn biết nhiều hơn về điều này ...).

(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

0x2alà 42 (foo) và 0x54là 84 (bar).

Trong cả hai trường hợp, sử dụng &nhoặc &csẽ cung cấp cho chúng tôi địa chỉ X. Đối với các loại giá trị, đó là những gì chúng tôi muốn, nhưng không dành cho các loại tham chiếu.

Khi làm:

let referencePointer = UnsafeMutablePointer<C>(&c)

Chúng tôi tạo một con trỏ trên tham chiếu, tức là một con trỏ trỏ đến địa chỉ X. Điều tương tự khi sử dụng 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)

Bây giờ chúng ta đã hiểu rõ hơn về những gì diễn ra dưới mui xe và bây giờ chúng ta sẽ tìm thấy địa chỉ Y (đó là địa chỉ chúng ta muốn), chúng ta có thể làm như sau để có được nó:

let addressY = unsafeBitCast(c, to: Int.self)

Đang xác minh:

(lldb) frame variable addressY -f hex
(Int) addressY = 0x0000000101b2fd20
(lldb) frame variable c
(testmem.C) c = 0x0000000101b2fd20 (foo = 42, bar = 84)

Có nhiều cách khác để làm điều này:

let addressY1 = Int(bitPattern: Unmanaged.passUnretained(c).toOpaque())
let addressY2 = withUnsafeMutableBytes(of: &c) { $0.load(as: Int.self) }

toOpaque()thực sự gọi unsafeBitCast(c, to: UnsafeMutableRawPointer.self).

Tôi hy vọng điều này đã giúp ... nó đã làm cho tôi.


Chỉ cần lưu ý rằng trong khi cố gắng in địa chỉ của cùng một cấu trúc thông qua 2 trường hợp khác nhau MemoryLocationtạo ra 2 địa chỉ khác nhau.
dùng1046037

@ user1046037 Cảm ơn, đã thực hiện thay đổi cho lớp init. Tôi cũng nhận được hai địa chỉ khác nhau, nhưng chỉ khi tôi sử dụng một cấu trúc trống. Sử dụng struct rỗng luôn mang lại cho tôi kết quả kỳ lạ. Tôi đoán là trình biên dịch thực hiện một số tối ưu hóa ...
nyg

@ user1046037 Kiểm tra: pastebin.com/mpd3ujw2 . Rõ ràng, tất cả các điểm cấu trúc trống đến cùng một địa chỉ bộ nhớ. Tuy nhiên, khi chúng ta muốn lưu trữ con trỏ trong một biến, nó sẽ tạo một bản sao của nó (hoặc của cấu trúc?) ...
nyg

Điều đó thật thú vị nhưng khi được in hai lần, nó sẽ in các địa chỉ bộ nhớ khác nhau. Tương tự là trường hợp với câu trả lời ở trên là tốt.
dùng1046037

@ user1046037 Tôi không chắc là tôi hiểu ý của bạn, bạn có mã nào không? (Tôi luôn nhận được cùng một địa chỉ bộ nhớ)
nyg

15

Các loại tham khảo:

  • Nó có ý nghĩa để có được địa chỉ bộ nhớ của một loại tham chiếu vì nó đại diện cho danh tính.
  • === toán tử nhận dạng được sử dụng để kiểm tra 2 đối tượng trỏ đến cùng một tham chiếu.
  • Sử dụng ObjectIdentifierđể lấy địa chỉ bộ nhớ

Mã số:

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

Các loại giá trị:

  • Nhu cầu lấy địa chỉ bộ nhớ của một loại giá trị không có nhiều ý nghĩa (vì nó là một giá trị) và sự nhấn mạnh sẽ nhiều hơn vào sự bình đẳng của giá trị.

12

Chỉ cần sử dụng này:

print(String(format: "%p", object))

Nếu bạn nhận được khiếu nại của trình biên dịch về " MyClass?" không phù hợp với CVarArg, bạn có thể làm extension Optional : CVarArg { }. Mặt khác, điều này dường như in địa chỉ mà không có sự điên rồ "không an toàn" của các câu trả lời khác.
Ngõ Devin

Nó đòi hỏi phải thực hiện var _cVarArgEncoding: [Int]trên CVarArg. Không rõ làm thế nào nên được thực hiện.
Yuchen Zhong

10

Nếu bạn chỉ muốn thấy điều này trong trình gỡ lỗi và không làm gì khác với nó, thì thực sự không cần phải lấy Intcon trỏ. Để có được chuỗi đại diện của địa chỉ của một đối tượng trong bộ nhớ, chỉ cần sử dụng một cái gì đó như thế này:

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)
    }
}

Ví dụ sử dụng:

print(self.pointerString, "Doing something...")
// Prints like: 0x7fd190d0f270 Doing something...

Ngoài ra, hãy nhớ rằng bạn có thể chỉ cần in một đối tượng mà không ghi đè lên đối tượngdescription đó và nó sẽ hiển thị địa chỉ con trỏ của nó bên cạnh văn bản mô tả (nếu là mật mã).

print(self, "Doing something else...")
// Prints like: <MyModule.MyClass: 0x7fd190d0f270> Doing something else...
// Sometimes like: <_TtCC14__lldb_expr_668MyModule7MyClass: 0x7fd190d0f270> Doing something else...

1
Hãy kèm theo bất kỳ downvote nào với một bình luận giải thích lý do tại sao, vì vậy tôi và bất kỳ ai khác đến đây đều biết tại sao đây là một giải pháp kém :)
Ben Leggiero

1
Đơn giản và gọn gàng!
badhanganesh

9

Swift 5

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)
    }
}

Sử dụng:

print("FileManager.default: \(String.pointer(FileManager.default))")
// FileManager.default: 0x00007fff5c287698

print("nil: \(String.pointer(nil))")
// nil: nil

Câu trả lời này không chính xác. Nếu bạn tạo hai thể hiện của cùng một lớp, nó sẽ trả về cùng một địa chỉ bộ nhớ cho cả hai thể hiện. Unmanaged.passUnretained(myObject).toOpaque()hoạt động đúng thay thế.
Padraig

@Padraig Cảm ơn, tôi đã cập nhật mã của bạn. Đáng buồn là bây giờ nó có một AnyObjecttham số. Tôi thích Anyloại đầu vào.
neoneye

6

Trong Swift4 về Mảng:

    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)
    }

1
đã cứu ngày của tôi. Cần có một huy hiệu "việc mua lại hữu ích gần đây nhất"
Anton Tropashko

Thật vậy, đây là cách tiếp cận duy nhất in của tôi self?.array.
Rostyslav Druzhunn

4

Các câu trả lời khác đều ổn, mặc dù tôi đang tìm cách lấy địa chỉ con trỏ dưới dạng số nguyên:

let ptr = unsafeAddressOf(obj)
let nullPtr = UnsafePointer<Void>(bitPattern: 0)

/// This gets the address of pointer
let address = nullPtr.distanceTo(ptr) // This is Int

Chỉ cần theo dõi một chút.


Xem dưới đây cho một phiên bản của câu trả lời này cho Swift 3.
RenniePet

3

Câu trả lời @Drew cung cấp chỉ có thể được sử dụng cho loại lớp.
Câu trả lời @nschum cung cấp chỉ có thể dành cho kiểu cấu trúc.

Tuy nhiên nếu bạn sử dụng phương thức thứ hai để lấy địa chỉ của một mảng có phần tử kiểu giá trị. Swift sẽ sao chép toàn bộ mảng vì trong mảng Swift là copy-on-write và Swift không thể đảm bảo nó hoạt động theo cách này một khi nó chuyển quyền kiểm soát sang C / C ++ (được kích hoạt bằng cách sử dụng &để lấy địa chỉ). Và nếu bạn sử dụng phương thức đầu tiên thay vào đó, nó sẽ tự động chuyển đổi Arraythành NSArrayđiều chắc chắn là điều chúng tôi không muốn.

Vì vậy, cách đơn giản và thống nhất nhất mà tôi tìm thấy là sử dụng hướng dẫn lldb frame variable -L yourVariableName.

Hoặc bạn có thể kết hợp câu trả lời của họ:

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

Đây là cho Swift 3.

Giống như @CharlieMonroe Tôi muốn lấy địa chỉ dưới dạng số nguyên. Cụ thể, tôi muốn địa chỉ của một đối tượng Thread để sử dụng làm ID luồng trong mô-đun ghi nhật ký chẩn đoán, cho các tình huống không có tên luồng.

Dựa trên mã của Charlie Monroe, đây là những gì tôi nghĩ ra cho đến nay. Nhưng hãy cẩn thận, tôi rất mới với Swift, điều này có thể không đúng ...

  // 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

Tuyên bố cuối cùng là ở đó bởi vì không có nó, tôi đã nhận được các địa chỉ như 0x60000007DB3F. Hoạt động modulo trong câu lệnh cuối chuyển đổi nó thành 0x7DB3F.


3

Giải pháp của tôi trên Swift 3

extension MyClass: CustomStringConvertible {
    var description: String {
        return "<\(type(of: self)): 0x\(String(unsafeBitCast(self, to: Int.self), radix: 16, uppercase: false))>"
    }
}

mã này tạo mô tả như mô tả mặc định <MyClass: 0x610000223340>


2

Đây chắc chắn không phải là cách nhanh nhất hoặc an toàn nhất để đi về nó. Nhưng nó làm việc cho tôi. Điều này sẽ cho phép bất kỳ lớp con nsobject nào chấp nhận thuộc tính này.

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

cảm ơn về phản hồi của Jeff, tôi sẽ cập nhật câu trả lời
Charlton Provatas

1
Đừng bận tâm! Đó là sai lầm của tôi! Mã của bạn hoạt động tốt với một lớp Swift thuần túy. Xin lỗi vì những lỗi lầm.
Jeff
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.