Передача быстрой ссылки на базовый код C и возврат его обратно на обратный вызов [дубликат]

Проблема заключается не в методе push для Array.prototype, а в ваших привязках. Вы изменяете один и тот же объект s на каждой итерации вашего блока async.foreach, который на самом деле является тем же объектом, что и ранее определенный Subscriber.

Сначала вы должны перенести объявление s переменная к блоку foreach.

А также, если вы хотите создать объект со значениями по умолчанию, он должен быть function, который возвращает новый объект:

function Subscriber() {
  return {
    'userID':   '',
    'email':    '',
    'name':     '',
    'stage':    '',
    'poster':   false,
    'canEmail': false,
    'stage':    ''
  };
};

И тогда вы можете создать экземпляр объекта Subscriber следующим образом:

var s = Subscriber();

Подробнее см. этот ответ или Закрытие на MDN .

30
задан Martin R 8 March 2017 в 11:19
поделиться

4 ответа

Указатель объекта (т. е. экземпляр ссылочного типа ) можно преобразовать в UnsafePointer<Void> (отображение Swift const void *, UnsafeRawPointer в Swift 3) и обратно. В Objective-C вы должны написать

void *voidPtr = (__bridge void*)self;
// 
MyType *mySelf = (__bridge MyType *)voidPtr;

(см. 3.2.4 Модифицированные броски в документации Clang ARC для точного значения этих приведений.)

Для этой цели Swift имеет тип Unmanaged. Это немного громоздко использовать, потому что он работает с COpaquePointer вместо UnsafePointer<Void>. Вот два вспомогательных метода (названных в честь создания Objective-C __bridge):

func bridge<T : AnyObject>(obj : T) -> UnsafePointer<Void> {
    return UnsafePointer(Unmanaged.passUnretained(obj).toOpaque())
    // return unsafeAddressOf(obj) // ***
}

func bridge<T : AnyObject>(ptr : UnsafePointer<Void>) -> T {
    return Unmanaged<T>.fromOpaque(COpaquePointer(ptr)).takeUnretainedValue()
    // return unsafeBitCast(ptr, T.self) // ***
}

«Сложное» выражение необходимо только для того, чтобы удовлетворить строгую систему Swifts. В скомпилированном коде это просто бросок между указателями. (Он может быть написан короче, как указано в комментариях ***, если вы готовы использовать «небезопасные» методы, но скомпилированный код идентичен.)

Используя эти вспомогательные методы, вы можете передать self к функции C как

 let voidPtr = bridge(self)

(или UnsafeMutablePointer<Void>(bridge(self)), если для функции C требуется изменяемый указатель) и преобразовать ее обратно в указатель объекта - например в функции обратного вызова - как

 let mySelf : MyType = bridge(voidPtr)

Передача права собственности не выполняется, поэтому вы должны убедиться, что self существует до тех пор, пока используется указатель void.


И для полноты, эквивалент Swift __bridge_retained и __bridge_transfer из Objective-C будет

func bridgeRetained<T : AnyObject>(obj : T) -> UnsafePointer<Void> {
    return UnsafePointer(Unmanaged.passRetained(obj).toOpaque())
}

func bridgeTransfer<T : AnyObject>(ptr : UnsafePointer<Void>) -> T {
    return Unmanaged<T>.fromOpaque(COpaquePointer(ptr)).takeRetainedValue()
}

bridgeRetained(), набрасывает указатель на указатель на пустоту и сохраняет объект , bridgeTransfer() преобразует указатель void обратно в указатель объекта и потребляет сохранение.

Преимущество заключается в том, что объект не может быть освобожден между вызовами, потому что поддерживается сильная ссылка. Недостатком является то, что вызовы должны быть правильно сбалансированы и что он может легко вызвать циклы сохранения.


Обновление для Swift 3 (Xcode 8):

func bridge<T : AnyObject>(obj : T) -> UnsafeRawPointer {
    return UnsafeRawPointer(Unmanaged.passUnretained(obj).toOpaque())
}

func bridge<T : AnyObject>(ptr : UnsafeRawPointer) -> T {
    return Unmanaged<T>.fromOpaque(ptr).takeUnretainedValue()
}

func bridgeRetained<T : AnyObject>(obj : T) -> UnsafeRawPointer {
    return UnsafeRawPointer(Unmanaged.passRetained(obj).toOpaque())
}

func bridgeTransfer<T : AnyObject>(ptr : UnsafeRawPointer) -> T {
    return Unmanaged<T>.fromOpaque(ptr).takeRetainedValue()
}

соответствующие изменения в «небезопасных указателях» описаны в

76
ответ дан Martin R 15 August 2018 в 14:51
поделиться
  • 1
    Извините за поздний ответ и спасибо за это. UnsafeMutablePointer (Unmanaged.passUnretained (self) .toOpaque ()) - способ его передачи. И приятно иметь эти мостовые методы для преобразования указателя. Спасибо. – Peter Peng 26 October 2015 в 03:27
  • 2
    Благодаря!! Потрачено столько времени на эту проблему – marchinram 18 April 2016 в 00:23
  • 3
    Можно ли использовать такой подход следующим образом: 1. Перейдите в сохраненный Box с переменной weak в self. 2. Callback опционально указывает значение на сильное. 3. Если экземпляр освобожден и Box содержит nil, обратный вызов потребляет сохранение Box? – Kirsteins 13 May 2016 в 09:21
  • 4
    @Kirsteins: Это должно быть возможно, но вам все равно придется отменить обратный вызов, если экземпляр освобожден. Возможно, было бы проще передать неиспользуемый указатель и отменить регистрацию обратного вызова в методе deinit экземпляра. – Martin R 16 May 2016 в 10:23
  • 5
    К сожалению, я могу только ответить на этот ответ один раз! – matt 26 February 2017 в 21:17

Этот ответ не выглядит как конкретный для обратного вызова как ответ Мартина R , но может быть полезным ...

Обычно вы можете передать значение любого типа небезопасному указателю void с помощью оператора &:

func baz(p: UnsafeMutablePointer<Void>) -> String {
    return "\(p)"
}

var num = 5
print(baz(&num))

Однако, чтобы пройти self, вам нужно сделать это в контексте, где self является изменяемым. Это означает, что вам нужно сделать это в методе мутации (или init) типа значения, а не в качестве ссылочного типа:

struct FooValue {
    mutating func bar() {
        print(baz(&self))
    }
}

var myFooValue = FooValue()
myFooValue.bar()

Если вы хотите использовать ссылочный тип, вы 'нужно создать локальную копию ссылки и передать указатель на это:

class FooReference {
    func bar() {
        var localSelf = self
        print(baz(&localSelf))
    }
}

let myFooReference = FooReference()
myFooReference.bar()
0
ответ дан Community 15 August 2018 в 14:51
поделиться

Мне кажется, что это то, что withUnsafeMutablePointer для - преобразовать произвольный указатель Swift в указатель C. По-видимому, вы могли бы это сделать (я не пробовал, но проверенный мной код работает безопасно):

var mself = self 
withUnsafeMutablePointer(&mself) { v in
    let v2 = UnsafeMutablePointer<Void>(v)
    myStruct.inputProcRefCon = v2
}
3
ответ дан matt 15 August 2018 в 14:51
поделиться
  • 1
    Обратите внимание, что будут проблемы с управлением памятью; "небезопасный изменяемый указатель" означает, что сохранение того, что находится на дальнем конце указателя, до you . Поэтому я думаю, что var mself = self нужно будет заменить постоянным глобальным. – matt 23 October 2015 в 15:27
  • 2
    Это передает адрес mself функции C, а не адрес объекта. Как вы сказали, mself должен быть глобальным, что я считаю довольно неэлегантным. - Код из stackoverflow.com/a/30788165/341994 выглядит сложным, но на самом деле ничего не делает. Он просто передает указатель объекта self в изменяемый указатель. На самом деле его можно упростить let observer = unsafeAddressOf(self), сгенерированный код сборки, похоже, идентичен. – Martin R 23 October 2015 в 17:44
  • 3
    (Продолжение) Преимущество явного (сложного) выражения заключается в том, что оно соответствует обратному преобразованию из указателя void в указатель объекта и что его можно изменить, чтобы сохранить объект. – Martin R 23 October 2015 в 17:47
  • 4
    Фактически обратное преобразование можно упростить, используя unsafeBitCast() ... – Martin R 23 October 2015 в 18:07
  • 5
    @MartinR Ты меня не обижаешь. Я тебя обманываю! Мой ответ был предназначен, чтобы побудить вас написать реальное объяснение, и это именно то, что вы сделали. Благодаря! :) – matt 25 October 2015 в 19:45
func bridge<T : AnyObject>(obj : T) -> UnsafePointer<Void> {
return UnsafePointer(Unmanaged.passUnretained(obj).toOpaque())
}


func bridge<T : AnyObject>(ptr : UnsafePointer<Void>) -> T {
return Unmanaged<T>.fromOpaque(ptr).takeUnretainedValue()
}

func bridgeRetained<T : AnyObject>(obj : T) -> UnsafePointer<Void> {
return UnsafePointer( Unmanaged.passRetained(obj).toOpaque())}

func bridgeTransfer<T : AnyObject>(ptr : UnsafePointer<Void>) -> T {
return Unmanaged<T>.fromOpaque(ptr).takeRetainedValue()}
2
ответ дан Mike 15 August 2018 в 14:51
поделиться
Другие вопросы по тегам:

Похожие вопросы: