我正在审核一些Alamofire sample Retrier代码:
func should(_ manager: SessionManager, retry request: Request, with error: Error, completion: @escaping RequestRetryCompletion) {
lock.lock() ; defer { lock.unlock() }
if let response = request.task.response as? HTTPURLResponse, response.statusCode == 401 {
requestsToRetry.append(completion)
if !isRefreshing {
refreshTokens { [weak self] succeeded, accessToken, refreshToken in
guard let strongSelf = self else { return }
strongSelf.lock.lock() ; defer { strongSelf.lock.unlock() }
...
}
}
} else {
completion(false, 0.0)
}
}
我不遵循如何在函数的第一行上使用lock.lock()
,然后在闭包中将同一行strongSelf.lock.lock()
传递给refreshTokens
。
如果在执行should
解锁时defer
方法结束之前没有释放第一个锁,那么在第一个锁被执行时第二个strongSelf.lock.lock()
如何成功执行?
答案 0 :(得分:4)
调用<div id="map-canvas"></div>
<script src="https://maps.googleapis.com/maps/api/js"></script>
<script>
var map;
function initialize() {
var mapOptions = {
center: new google.maps.LatLng(40.7127837, -74.0059413),
zoom: 11,
mapTypeId: google.maps.MapTypeId.ROADMAP
};
map = new google.maps.Map(document.getElementById("map-canvas"),
mapOptions);
var myLatlng = new google.maps.LatLng(40.7127837, -74.0059413);
var marker = new google.maps.Marker({
position: myLatlng,
map: map,
title: "'. $xmladd .'"
});
var myLatlng2 = new google.maps.LatLng(40.735657, -74.1723667);
var marker2 = new google.maps.Marker({
position: myLatlng2,
map: map,
title: "'. $xmladd2 .'"
});
}
google.maps.event.addDomListener(window, 'load', initialize);
google.maps.event.addDomListener(window, "resize", function() {
var center = map.getCenter();
google.maps.event.trigger(map, "resize");
map.setCenter(center);
});
</script>
/ refreshTokens
的第二次调用的lock()
的尾随闭包是异步运行的。这是因为闭包是unlock()
,并且是在@escaping
例程内的responseJSON
内调用的。因此,refreshTokens
方法在实际调用should
的关闭时将执行其延迟unlock
。
话虽如此,这不是我见过的最优雅的代码,其中锁的效用不明确,死锁的风险依赖于其他例程的实现细节。它看起来好像在这里,但我不会责怪你挑眉。