I've been think how can this be reliably implemented for ObjC weak
references. And I think associated objects is the answer. I can
emulate side table behaviour by storing an associated object and using
identity of that object as a key.

This approach sounds like a reliable solution for Swift as well, but
for Swift it is suboptimal. I would prefer to use associated objects
approach as a fallback, and still have a fast path for native Swift
reference counting.

What if you stick the weak references into a dictionary indexed by
ObjectIdentifer and identified by serial number? Identify each WeakRef
by the serial number corresponding to the referenced object, if any has
already been assigned; otherwise, assign a new serial number. See the
following code, which I haven't even tried to compile:

struct WeakRef {
	private struct ExtantRecord {
		weak var object: MyClass?
		var serialNumber: UInt64
	}
	private static var nextSerialNumber: UInt64 = 0
	private static var extantWeakRefs: Dictionary<ObjectIdentifer,
	    > = [:]

	private var serialNumber: UInt64

	func hash(into hasher: inout Hasher) {
		hasher.combine(l.serialNumber)
	}
	static func ==(_ l: WeakRef, _ r: WeakRef) -> Bool {
		return l.serialNumber == r.serialNumber
	}
	init(object o: MyClass) {
		let oid = ObjectIdentifier(o)

		// TBD synchronize access to extantWeakRefs, nextSerialNumber
		guard let extant = extantWeakRefs[oid], extant.object === o
		    else {
			serialNumber = nextSerialNumber
			nextSerialNumber = nextSerialNumber + 1
			extantWeakRefs[oid] = ExtantRecord(object: o,
			    serialNumber: serialNumber)
			// Collect garbage after every 1024 records.
			if serialNumber % 1024 == 0 {
				collectGarbage()
			}
			return
		}
		serialNumber = extant.serialNumber
	}
	// Remove records of weak refs that have changed to nil. 
	private static func collectGarbage() {
		// TBD synchronize access to extantWeakRefs
		extantWeakRefs = extantWeakRefs.compactMapValues() { extant in
		    (extant.object == nil) ? nil : extant
		}
	}
}

Dave