初始化GMSMarkers的功能:
func makeMarkers (progressHandler: ((String) -> Void)? = nil) {
progressHandler?("Инициализируем маркеры...")
for device in self.devices {
progressHandler?("Инициализируем маркеры: для устройства \(device.name!)...")
if let position = self.positions.findById(device.positionId) {
if let marker = DeviceMarker(device, at: position) {
self.deviceMarkers.append(marker)
}
}
}
for geofence in self.geofences {
progressHandler?("Инициализируем маркеры: для геометки \(geofence.name!)...")
if let marker = GeofenceMarker(geofence) {
self.geofenceMarkers.append(marker)
}
}
self.locationManager.requestLocation()
progressHandler?("Инициализируем маркеры: для пользователя \(self.loggedUser.name!)...")
if let userLocation = self.locationManager.location {
self.userMarker = UserMarker(self.loggedUser, at: userLocation)
} else {
self.userMarker = UserMarker(self.loggedUser, at: CLLocation(latitude: 48, longitude: 44))
}
progressHandler?("Маркеры инициализированы...")
}
如您所见,我希望使用progressHandler告知用户此操作的进度。
但在执行该功能时,我看不到任何消息。 剪断我调用函数makeMarkers的地方:
...
DB.geofences.server.getAll() { geofences in
self.statusLabel.text = "Получили геометки \(geofences.count)..."
DB.devices.server.getAll() { devices in
self.statusLabel.text = "Получили устройства \(devices.count)..."
DB.positions.server.getAll() { positions in
self.statusLabel.text = "Получили позиции \(positions.count)..."
DB.devices.client.insert(devices)
self.statusLabel.text = "Записали устройства..."
DB.positions.client.insert(positions)
self.statusLabel.text = "Записали позиции..."
DB.geofences.client.insert(geofences)
self.statusLabel.text = "Записали геометки..."
MapManager.shared.makeMarkers() { status in
self.statusLabel.text = status
}
...
如果我使用print()更改查看消息,将显示所有消息。 所以,问题是:为什么在执行我的函数期间阻止了UI更改以及如何摆脱它?
更新:当然,我在主线程中做了所有事情。
更新2:我正在调用我的函数更新的代码片段。在地图控制器显示之前我可以看到的最后一条消息是“Получилиустройства...”,这很奇怪,因为我确定我也能获得位置
答案 0 :(得分:2)
嗯,这是因为UI更新发生在主线程中。但是当您更改标签的文本时,此更改不会立即发生。相反,所有UI更改都会被调度,并且只有在应用程序完成当前通过事件循环时才会呈现。
由于您在同一主循环中执行耗时的任务,因此它会被阻止,并且在这些任务完成并且函数返回之前不会发生更改。
您可以查看这些文章,详细了解事件循环的工作原理:Run Loops,Main event loop
我建议您将所有耗时的任务(例如数据库查询)移到后台线程,并在您真正想要更新UILabel时从那里调用主线程。