robreuss / VirtualGameController

Software-based game controllers for iOS, tvOS, OS X and watchOS in Swift 4.2.
MIT License
462 stars 44 forks source link

Race condition causing elements to return incorrect values after connecting #17

Closed ay8s closed 8 years ago

ay8s commented 8 years ago

Currently testing things out a little more with more devices connecting to a tvOS app. If I have the peripherals searching for the Central and then publish the central all of the controllers connect correctly.

Within my controllerDidConnect I setup logic to receive an avatar and a string. These get sent from the peripheral straight after connecting but it seems they can get mixed up with some strings/avatars duplicating & populating incorrectly against other controllers.

I also tried delaying the sending to a second, it seems to improve things but you can still get an incorrect string/avatar being returned in the valueChangedHandler.

@robreuss I have pushed this to my repo if that helps debug things at all. I have 5 devices connecting pretty much instantly when I publish the service.

robreuss commented 8 years ago

It looks like you are sending the avatar and string immediately (after 1 sec delay) calling VgcManager.peripheral.connectToService.

Instead it would be better if you wait and send those after you receive the VgcPeripheralDidConnectNotification notification.

Let me know if that works!

robreuss commented 8 years ago

Ignore that last comment - you are in fact handling it correctly. Looking now for other causes!

robreuss commented 8 years ago

I think I got this figured out. When defining your valueChangedHandler for image and name, you were using the same var controller internal to the block as you were in assigning the handler. If the var internal to the handler block has a different name, thing seem to work properly:

        // Avatar Image
        controller.elements.custom[CQVGCCustomElementType.ProfileAvatarImage.rawValue]!.valueChangedHandler = { (con , element) in

            dispatch_async(dispatch_get_main_queue()) {

                if let playerView = self.playerToView[con] {
                    playerView.avatarImageView.image = UIImage(data: element.value as! NSData)
                    self.playerToAvatar[con] = UIImage(data: element.value as! NSData)
                }
            }
        }

I do the same thing in my samples so it's understandable that you did it!

robreuss commented 8 years ago

Unfortunately, that was not the fix - I started seeing the duplicate avatars again. By switching to the standard "image" element, I was able to fix the problem, and so zeroed in on a problem with how custom elements were copied. I've fixed that and pushed the changes, so if you pull master, it should be working correctly now!

ay8s commented 8 years ago

That looks to be working correctly now @robreuss :+1: