AVPlayer not playing in Xcode12 - ios

I'm trying to play an video from photo library with AVPlayer but for some reason I can't get it to work. I've been trying to read every question about this but none of the suggested answers seems to work.
Is my code wrong or do I need to do something else to make it work? Enable it in capabilities or something similar?
class ViewController: UIViewController, UIImagePickerControllerDelegate, UINavigationControllerDelegate {
let videoPickerController = UIImagePickerController()
// MARK:- UI Elements
let SelectVideoBtn : UIButton = {
let a = UIButton(type: .roundedRect)
a.translatesAutoresizingMaskIntoConstraints = false
a.setTitle("Select Video", for: .normal)
a.backgroundColor = UIColor.systemOrange
a.layer.cornerRadius = 10
a.addTarget(self, action: #selector(SelectAVideo(sender:)), for: .touchUpInside)
return a
}()
let MasterPreviewView : UIView = {
let a = UIView()
a.translatesAutoresizingMaskIntoConstraints = false
a.backgroundColor = #colorLiteral(red: 0.9098039269, green: 0.4784313738, blue: 0.6431372762, alpha: 1)
a.layer.cornerRadius = 10
return a
}()
let HorizontalToolStack : UIStackView = {
let a = UIStackView()
a.translatesAutoresizingMaskIntoConstraints = false
a.axis = .horizontal
a.distribution = .equalSpacing
a.alignment = .fill
a.spacing = 20
return a
}()
override func viewDidLoad() {
super.viewDidLoad()
self.view.backgroundColor = #colorLiteral(red: 0.9764705896, green: 0.850980401, blue: 0.5490196347, alpha: 1)
// Do any additional setup after loading the view.
// delegates and data stuff
videoPickerController.delegate = self
// Selection Button
self.view.addSubview(SelectVideoBtn)
SelectVideoBtn.topAnchor.constraint(equalTo: self.view.topAnchor, constant: 30).isActive = true
SelectVideoBtn.leadingAnchor.constraint(equalTo: self.view.leadingAnchor, constant: 100).isActive = true
SelectVideoBtn.widthAnchor.constraint(equalToConstant: 200).isActive = true
SelectVideoBtn.heightAnchor.constraint(equalToConstant: 50).isActive = true
// Master Preview View
self.view.addSubview(MasterPreviewView)
MasterPreviewView.topAnchor.constraint(equalTo: SelectVideoBtn.bottomAnchor, constant: 30).isActive = true
MasterPreviewView.leadingAnchor.constraint(equalTo: self.view.leadingAnchor, constant: 10).isActive = true
MasterPreviewView.trailingAnchor.constraint(equalTo: self.view.trailingAnchor, constant: -10).isActive = true
MasterPreviewView.heightAnchor.constraint(equalToConstant: 400).isActive = true
MasterPreviewView.isUserInteractionEnabled = false
let videoURL = NSURL(string: "assets-library://asset/asset.MP4?id=A0FBB444-15D7-4ED2-9EB2-922E4FB11F7A&ext=MP4")
PlayVideo(inView: MasterPreviewView, pathToVideo: videoURL!)
}
internal func VideoPicker(){
videoPickerController.sourceType = .photoLibrary
videoPickerController.mediaTypes = ["public.movie"]
videoPickerController.allowsEditing = true
present(videoPickerController, animated: true, completion: nil)
}
// MARK:- Delegate Methods
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {
let videoURL = info[UIImagePickerController.InfoKey(rawValue: "UIImagePickerControllerReferenceURL")] as? NSURL
print(videoURL!)
videoPickerController.dismiss(animated: true, completion: nil)
// Now Play the Selected Video
PlayVideo(inView: MasterPreviewView, pathToVideo: videoURL!)
}
public func imagePickerControllerDidCancel(_ picker: UIImagePickerController) {
print("Selection Cancelled")
self.dismiss(animated: true, completion: nil)
}
// MARK:- Button Selectors
#objc func SelectAVideo(sender : UIButton){
VideoPicker()
}
//MARK:- Custom Functions
/**
A function to play a video in the View of our choice.
- Parameter inView : Specify the view in which youo want the video player to play your video
- Parameter pathToVide : The path of the video you want to play
*/
private func PlayVideo(inView parentView : UIView, pathToVideo urlPath : NSURL) {
// Downcasting the NSURL to URL
let player = AVPlayer(url: urlPath as URL)
let playerController = AVPlayerViewController()
playerController.player = player
let playerLayerAV = AVPlayerLayer(player: player)
//now we set the size of frame to be like the view ("backview")
playerLayerAV.frame = parentView.bounds
parentView.layer.addSublayer(playerLayerAV)
player.play()
player.rate = 0.5
}
}

Related

Detect if volume button is pressed when app is running in the background - Swift iOS

Goal and Question: My goal is to have my application launch when the user presses the volume up button three times. Is it possible to enable this functionality and if so, how?
I've realized that when using the "Audio, AirPlay, and Picture in Picture" background mode, it's possible to register that the volume button was tapped, even when the display is off and the app is running in the background. However, this only works if audio is playing from the app. When audio isn't playing, pressing the volume button isn't registered when the app is in the background.
Audio boxed checked in Background mode
I used this code to test out this feature, courtesy of https://github.com/rebeloper/BackgroundModesSwift/tree/master/BackgroundModesSwift
Here's the audio view controller, I slightly modified it from the original code on Github to include the listenVolumeButton(), viewWillAppear(), and the first if statement in observeValue()
import TinyConstraints
import AVFoundation
class AudioViewController: UIViewController {
var counter = 1
lazy var player: AVQueuePlayer = self.makePlayer()
var outputVolumeObserve: NSKeyValueObservation?
let audioSession = AVAudioSession.sharedInstance()
private lazy var songs: [AVPlayerItem] = {
let songNames = ["Getting it Done"]
return songNames.map {
let url = Bundle.main.url(forResource: $0, withExtension: "mp3")!
return AVPlayerItem(url: url)
}
}()
lazy var songLabel: UILabel = {
var label = UILabel()
label.font = UIFont.boldSystemFont(ofSize: 34)
label.textColor = #colorLiteral(red: 0.1764705882, green: 0.2039215686, blue: 0.2117647059, alpha: 1)
return label
}()
lazy var timeLabel: UILabel = {
var label = UILabel()
label.font = UIFont.systemFont(ofSize: 28)
label.textColor = #colorLiteral(red: 0.1764705882, green: 0.2039215686, blue: 0.2117647059, alpha: 1)
return label
}()
lazy var playPauseButton: UIButton = {
var button = UIButton()
button.setTitle(button.isSelected ? "Pause" : "Play", for: .normal)
button.titleLabel?.font = UIFont.boldSystemFont(ofSize: 16)
button.setTitleColor(#colorLiteral(red: 1, green: 1, blue: 1, alpha: 1), for: .normal)
button.backgroundColor = #colorLiteral(red: 0.03529411765, green: 0.5176470588, blue: 0.8901960784, alpha: 1)
button.layer.cornerRadius = 8
button.layer.masksToBounds = true
button.addTarget(self, action: #selector(playPauseAction(_:)), for: .touchUpInside)
return button
}()
#objc func playPauseAction(_ sender: UIButton) {
sender.isSelected = !sender.isSelected
if sender.isSelected {
player.play()
} else {
player.pause()
}
playPauseButton.setTitle(playPauseButton.isSelected ? "Pause" : "Play", for: .normal)
}
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
setupViews()
addPeriodicTimeObserver()
}
func setupViews() {
view.backgroundColor = #colorLiteral(red: 0.9254901961, green: 0.9411764706, blue: 0.9450980392, alpha: 1)
view.addSubview(songLabel)
view.addSubview(timeLabel)
view.addSubview(playPauseButton)
songLabel.centerInSuperview(offset: CGPoint(x: 0, y: -20))
timeLabel.centerInSuperview(offset: CGPoint(x: 0, y: 30))
playPauseButton.edgesToSuperview(excluding: .top, insets: .bottom(10) + .right(10) + .left(10), usingSafeArea: true)
playPauseButton.height(50)
}
func addPeriodicTimeObserver() {
do {
try AVAudioSession.sharedInstance().setCategory(
AVAudioSession.Category.playAndRecord,
mode: .default,
options: [])
} catch {
print("Failed to set audio session category. Error: \(error)")
}
player.addPeriodicTimeObserver(forInterval: CMTimeMake(value: 1, timescale: 100), queue: DispatchQueue.main) { [weak self] time in
guard let self = self else { return }
let timeString = String(format: "%02.2f", CMTimeGetSeconds(time))
// TODO: check applicationState
}
}
private func makePlayer() -> AVQueuePlayer {
let player = AVQueuePlayer(items: songs)
player.actionAtItemEnd = .advance
player.addObserver(self, forKeyPath: "currentItem", options: [.new, .initial] , context: nil)
return player
}
override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
if keyPath == "outputVolume" {
counter += 1
print(counter)
}
if keyPath == "currentItem",
let player = object as? AVPlayer,
let currentItem = player.currentItem?.asset as? AVURLAsset {
songLabel.text = currentItem.url.lastPathComponent
}
}
func listenVolumeButton() {
do {
try audioSession.setActive(true)
} catch {
print("some error")
}
audioSession.addObserver(self, forKeyPath: "outputVolume", options: NSKeyValueObservingOptions.new, context: nil)
}
override func viewWillAppear(_ animated: Bool) {
listenVolumeButton()
}
}
Additionally, I was wondering if there is any way to programmatically use the shortcuts app that's preinstalled on iPhones to achieve this functionality, SwiftUI Widgets, or creating a notification that the operating system sends to the app when the volume button is pressed.
Any help is appreciated, Thank You in advance.

Protocol delegate not giving desired result

A simple profile page with an image to display based on what i select on the settings page, different files for controller and view, click on tick of profile go to settings page, select image1 or image2 and that image must display on profile page ,i try and create a protocol on settings to be able to add image , then implement a delegate on profile view file so that it can update the image its not working, can any one please point out my error
SettingsController
import UIKit
protocol ShowImage: class {
func displayImage(_ of: UIImage)
}
class SettingsController: UIViewController {
weak var delegate: ShowImage?
override func viewDidLoad() {
super.viewDidLoad()
let settings = SettingsView()
view.addSubview(settings.view)
settings.btn1.addTarget(self, action: #selector(dCode), for: .touchUpInside)
// Do any additional setup after loading the view.
}
#objc func dCode() {
let image = UIImage(named: "homei")
delegate?.displayImage(image!)
navigationController?.pushViewController(ProfileController(), animated: true)
}
}
SettingsView
import UIKit
class SettingsView: UIViewController {
var btn1 = UIButton()
var btn2 = UIButton()
override func viewDidLoad() {
super.viewDidLoad()
view.translatesAutoresizingMaskIntoConstraints = false
view.heightAnchor.constraint(equalToConstant: UIScreen.main.bounds.height).isActive = true
view.widthAnchor.constraint(equalToConstant: UIScreen.main.bounds.width).isActive = true
view.backgroundColor = UIColor.white
btn1.heightAnchor.constraint(equalToConstant: 30).isActive = true
btn1.widthAnchor.constraint(equalToConstant: 150).isActive = true
btn1.setTitleColor(UIColor.red, for: .normal)
btn1.backgroundColor = UIColor.green
btn2.heightAnchor.constraint(equalToConstant: 30).isActive = true
btn2.widthAnchor.constraint(equalToConstant: 150).isActive = true
btn2.setTitleColor(UIColor.red, for: .normal)
btn2.backgroundColor = UIColor.green
btn1.setTitle("Image1", for: .normal)
btn2.setTitle("Image2", for: .normal)
let stackP = UIStackView()
stackP.axis = .horizontal
stackP.alignment = .top
stackP.spacing = 10
stackP.distribution = .fill
stackP.addArrangedSubview(btn1)
stackP.addArrangedSubview(btn2)
stackP.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(stackP)
stackP.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
stackP.centerYAnchor.constraint(equalTo: view.centerYAnchor).isActive = true
// Do any additional setup after loading the view.
}
}
Profile Controller
import UIKit
class ProfileController: UIViewController {
let profile = ProfileView()
override func viewDidLoad() {
super.viewDidLoad()
view.addSubview(profile.view)
// Do any additional setup after loading the view.
profile.settingsBtn.addTarget(self, action: #selector(gotoSettings), for: .touchUpInside)
}
#objc func gotoSettings(){
let settings = SettingsController()
navigationController?.pushViewController(settings, animated: true)
}
}
Profile View
import UIKit
class ProfileView: UIViewController, ShowImage{
func displayImage(_ of: UIImage) {
apply(img: of)
}
var bgImage = UIImageView()
var settingsBtn = UIButton()
override func viewDidLoad() {
super.viewDidLoad()
view.translatesAutoresizingMaskIntoConstraints = false
view.heightAnchor.constraint(equalToConstant: UIScreen.main.bounds.height).isActive = true
view.widthAnchor.constraint(equalToConstant: UIScreen.main.bounds.width).isActive = true
bgImage.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(bgImage)
bgImage.heightAnchor.constraint(equalToConstant: UIScreen.main.bounds.height).isActive = true
bgImage.widthAnchor.constraint(equalToConstant: UIScreen.main.bounds.width).isActive = true
settingsBtn.heightAnchor.constraint(equalToConstant: 60).isActive = true
settingsBtn.widthAnchor.constraint(equalToConstant: 60).isActive = true
// settingsBtn.setTitle("Settings", for: .normal)
settingsBtn.setImage(UIImage(named: "tick"), for: .normal)
settingsBtn.backgroundColor = UIColor.red
settingsBtn.layer.cornerRadius = 5
view.addSubview(settingsBtn)
settingsBtn.translatesAutoresizingMaskIntoConstraints = false
settingsBtn.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -30).isActive = true
settingsBtn.topAnchor.constraint(equalTo: view.topAnchor, constant: 70).isActive = true
let set = SettingsController()
set.delegate = self
// Do any additional setup after loading the view.
}
func apply(img: UIImage)
{
bgImage.image = img
}
}
enter image description here
let set = SettingsController()
set.delegate = self
You're making a brand new SettingsController, setting its delegate... and then doing nothing with it. You probably want to find the existing SettingsController that is on the screen, though you have a very confusing system here with xView and xController, both of which are view controllers, so it's hard to know what's going on.

matchmakerViewController:didFindMatch is not being called after accepting Invite

I am making a real time Game Center game, with GameKit as a new programmer, however I have run into a few road blocks.
I am able to properly initialize the local player, present the matchmaking viewController, and receive and accept invites, however, even after I accept the invite matchmakerViewController:didFindMatch is not called and no match is returned to me. There is a high likelihood that I did not accept the invitation correct, but according to apples developer forums I have. If someone could review this code and let me know how to have that method be called that'd be great!
let request = GKMatchRequest()
class SecondScreenViewController : UIViewController, UINavigationControllerDelegate, GKMatchmakerViewControllerDelegate, GKLocalPlayerListener {
let button = UIButton()
let softRed = UIColor(red: 1, green: 61 / 255, blue: 61 / 255, alpha: 1)
let softblue = UIColor(red: 38 / 255, green: 149 / 255, blue: 1, alpha: 1)
let TestMatchMaker = GKMatchmaker()
let TestMatch = GKMatch()
var TestViewController = GKMatchmakerViewController(matchRequest: request)
var player = GKLocalPlayer.local
override func viewDidLoad() {
super.viewDidLoad()
player.register(self)
setupButton()
SetupRequest()
view.backgroundColor = softblue
}
func matchmakerViewControllerWasCancelled(_ viewController: GKMatchmakerViewController) {
dismiss(animated: true, completion: nil)
print("cancelled")
}
func matchmakerViewController(_ viewController: GKMatchmakerViewController, didFailWithError error: Error) {
print(error.localizedDescription + "THIS IS AN ERROR FROM THE VIEWCONTROLLER")
}
func matchmakerViewController(_ viewController: GKMatchmakerViewController, didFind match: GKMatch) {
print("Found Match Successfully")
let TestMatch = match
print(TestMatch)
}
func player(_ player: GKPlayer, didAccept invite: GKInvite) {
print(invite)
print("Aceppted Invite")
TestViewController?.setHostedPlayer(player, didConnect: true)
}
func player(_ player: GKPlayer, didRequestMatchWithRecipients recipientPlayers: [GKPlayer]) {
print("Requested Match")
}
func SetupRequest() {
request.minPlayers = 2
request.maxPlayers = 2
request.inviteMessage = "test Invite"
}
func setupButton() {
button.backgroundColor = UIColor.white
button.setTitleColor(softblue, for: .normal)
button.setTitle("MatchMake", for: .normal)
button.addTarget(self, action: #selector(ButtonTapped), for: .touchUpInside)
view.addSubview(button)
setupButtonConstraints()
}
func setupButtonConstraints() {
button.translatesAutoresizingMaskIntoConstraints = false
button.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 30).isActive = true
button.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -30).isActive = true
button.heightAnchor.constraint(equalToConstant: 100).isActive = true
button.centerYAnchor.constraint(equalTo: view.centerYAnchor, constant: 0).isActive = true
}
#objc func ButtonTapped() {
present(TestViewController!, animated: true, completion: {
self.TestViewController!.delegate = self})
TestViewController?.matchmakerDelegate = self
}
}
The only thing I see that might be causing it is when you set the matchmaker delegate. Here is the code I am using to invite players and it is working properly:
func invitePlayers(){
let request = GKMatchRequest()
request.minPlayers = 2
request.maxPlayers = 4
request.defaultNumberOfPlayers = 2
let vc = GKMatchmakerViewController(matchRequest: request)
vc?.matchmakerDelegate = self
self.present(vc!, animated: true)
}
notice that the matchmakerDelegate is set before the ViewController is presented.

Protocol and delegate pattern not calling the method

Implementing a protocol/delegate pattern as suggested by expert #DonMag, i am unable to get the code working...
I show a ratings window like below and when the user changes the ratings , i want the ratings emoji to update and the controller to pop, i also use animation, now for view i have a separate ratings class and for controller a separate class,
The problem is this function gets tapped , i can detect it but it does not reach the protocol method
#objc func ratingButtonTapped(_ sender: UIButton) {
// print(sender.titleLabel?.text)
guard let t = sender.titleLabel?.text else {
return
}
ratingDelegate?.defineTheratings(t)
}
Controller class
import UIKit
import CoreData
protocol RatingsPresentation: class {
func defineTheratings(_ ratings: String)
}
class RatingsViewController: UIViewController, RatingsPresentation {
func defineTheratings(_ ratings: String) {
print("ratings seleced\(ratings)")
self.restaurant.rating = ratings
if let appDelegate = (UIApplication.shared.delegate as? AppDelegate) {
appDelegate.saveContext()
}
if self.presentedViewController != nil {
self.dismiss(animated: true, completion: nil)
}
else {
self.navigationController?.popViewController(animated: true)
}
}
var restaurant: Restaurant!
var rates = RatingsView()
override func viewDidLoad() {
super.viewDidLoad()
view.addSubview(rates.view)
//Delegates
let vc = RatingsView()
// set the rating delegate
vc.ratingDelegate = self
//
if let restaurantImage = restaurant.image {
rates.bkgImageView.image = UIImage(data: restaurantImage as Data)
}
rates.crossBtn.addTarget(self, action: #selector(closeRatings), for: .touchUpInside)
let animateCross = CGAffineTransform(translationX: 1000, y: 0)
rates.crossBtn.transform = animateCross
}
#objc func closeRatings() {
navigationController?.popViewController(animated: true)
}
}
View Class
import UIKit
class RatingsView: UIViewController {
var bkgImageView = UIImageView()
var crossBtn = UIButton()
var btnCollection: [UIButton] = []
weak var ratingDelegate: RatingsPresentation?
override func viewDidLoad() {
super.viewDidLoad()
let ratings: [String] = ["cool", "happy","love", "sad", "angry"]
let animationBlur = UIBlurEffect(style: .dark)
let visualBlurView = UIVisualEffectView(effect: animationBlur)
// add elements to self
view.addSubview(bkgImageView)
view.addSubview(visualBlurView)
bkgImageView.translatesAutoresizingMaskIntoConstraints = false
visualBlurView.translatesAutoresizingMaskIntoConstraints = false
bkgImageView.topAnchor.constraint(equalTo: view.topAnchor).isActive = true
bkgImageView.leadingAnchor.constraint(equalTo: view.leadingAnchor).isActive = true
bkgImageView.trailingAnchor.constraint(equalTo: view.trailingAnchor).isActive = true
bkgImageView.bottomAnchor.constraint(equalTo: view.bottomAnchor).isActive = true
// constrain visualBlurView to all 4 sides
visualBlurView.topAnchor.constraint(equalTo: view.topAnchor).isActive = true
visualBlurView.leadingAnchor.constraint(equalTo: view.leadingAnchor).isActive = true
visualBlurView.trailingAnchor.constraint(equalTo: view.trailingAnchor).isActive = true
visualBlurView.bottomAnchor.constraint(equalTo: view.bottomAnchor).isActive = true
bkgImageView.contentMode = .scaleAspectFill
// Do any additional setup after loading the view.
//Add stackView
let stackEmoji = UIStackView()
stackEmoji.translatesAutoresizingMaskIntoConstraints = false
stackEmoji.axis = .vertical
stackEmoji.spacing = 5
stackEmoji.distribution = .fill
stackEmoji.alignment = .top
let font = UIFont(name: "Rubik-Medium", size: 28)
let fontM = UIFontMetrics(forTextStyle: .body)
ratings.forEach { (btn) in
let b = UIButton()
b.setTitle(btn, for: .normal)
b.titleLabel?.font = fontM.scaledFont(for: font!)
b.setImage(UIImage(named: btn), for: .normal)
stackEmoji.addArrangedSubview(b)
btnCollection.append(b)
//btn animation
let sizeAnimation = CGAffineTransform(scaleX: 5, y: 5)
let positionAnimation = CGAffineTransform(translationX: 1000, y: 0)
let combinedAninaton = sizeAnimation.concatenating(positionAnimation)
b.transform = combinedAninaton
b.addTarget(self, action: #selector(ratingButtonTapped(_:)), for: .touchUpInside)
}
view.addSubview(stackEmoji)
stackEmoji.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
stackEmoji.centerYAnchor.constraint(equalTo: view.centerYAnchor).isActive = true
// if let img = UIImage(named: "cross") {
// crossBtn.setImage(img, for: [])
// }
crossBtn.setTitle("X", for: [])
crossBtn.setTitleColor(.white, for: .normal)
crossBtn.setTitleColor(.gray, for: .highlighted)
crossBtn.titleLabel?.font = UIFont.systemFont(ofSize: 44, weight: .bold)
view.addSubview(crossBtn)
crossBtn.translatesAutoresizingMaskIntoConstraints = false
crossBtn.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -30).isActive = true
crossBtn.topAnchor.constraint(equalTo: view.topAnchor, constant: 150).isActive = true
}
#objc func ratingButtonTapped(_ sender: UIButton) {
// print(sender.titleLabel?.text)
guard let t = sender.titleLabel?.text else {
return
}
ratingDelegate?.defineTheratings(t)
}
}
Problem is here
var rates = RatingsView() //// shown 1
override func viewDidLoad() {
super.viewDidLoad()
view.addSubview(rates.view) /////// you add this as a subview
//Delegates
let vc = RatingsView() //////// this is useless - not shown 1
// set the rating delegate
vc.ratingDelegate = self ////// and set the delegate for this non-shown
So you need to remove let vc = RatingsView() and set the delegate for
rates.ratingDelegate = self

Swift: Screen Freezing from time to time when Dismissing a ViewController displaying a picture over the current context

I am having some troubles with: The screen freezing from time to time when Dismissing the ViewController displaying a picture over the current context.
May someone provide me some insights on how to fix this problem?
A sample of my codes is found below:
import UIKit
class ViewControllerCell: UICollectionViewCell {
override init(frame: CGRect) {
super.init(frame: frame)
backgroundColor = UIColor.white
addSubview(showPhotoButton)
showPhotoButton.leftAnchor.constraint(equalTo: leftAnchor, constant: 200).isActive = true
showPhotoButton.bottomAnchor.constraint(equalTo: topAnchor, constant: 160).isActive = true
showPhotoButton.heightAnchor.constraint(equalToConstant: 50).isActive = true
showPhotoButton.widthAnchor.constraint(equalToConstant: 70).isActive = true
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
lazy var showPhotoButton: UIButton = {
let button = UIButton(type: .system)
button.translatesAutoresizingMaskIntoConstraints = false
button.setTitle("Show", for: .normal)
button.addTarget(self, action: #selector(showSale), for: .touchUpInside)
button.setTitleColor(UIColor(r: 120, g: 80, b: 255), for: .normal)
return button
}()
#objc func showSale() {
let popupViewController = PopupViewController()
popupViewController.modalPresentationStyle = .overCurrentContext
popupViewController.modalTransitionStyle = UIModalTransitionStyle.crossDissolve
window!.rootViewController?.present(PopupViewController, animated: true, completion: nil)
}
}
import UIKit
class SalePopupViewController: UIViewController {
override func viewDidLoad() {
view.backgroundColor = UIColor(white: 1, alpha: 0.60)
view.isOpaque = false
view.addSubview(rebateImage)
view.addSubview(dismissButton)
dismissButton.topAnchor.constraint(equalTo: view.topAnchor).isActive = true
dismissButton.leftAnchor.constraint(equalTo: view.leftAnchor).isActive = true
dismissButton.bottomAnchor.constraint(equalTo: view.bottomAnchor).isActive = true
dismissButton.rightAnchor.constraint(equalTo: view.rightAnchor).isActive = true
rebateImage.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
rebateImage.centerYAnchor.constraint(equalTo: view.centerYAnchor, constant: -35).isActive = true
rebateImage.heightAnchor.constraint(equalToConstant: 290).isActive = true
rebateImage.widthAnchor.constraint(equalTo: view.widthAnchor, multiplier: 1).isActive = true
}
let dismissButton: UIButton = {
let button = UIButton(type: .system)
button.addTarget(self, action: #selector(dismissPopup), for: .touchUpInside)
button.translatesAutoresizingMaskIntoConstraints = false
return button
}()
let rebateImage: UIImageView = {
let image = UIImageView()
image.translatesAutoresizingMaskIntoConstraints = false
image.layer.masksToBounds = false
image.layer.cornerRadius = 2
image.contentMode = .scaleAspectFill
image.clipsToBounds = true
image.image = UIImage(named: "SaleCostco")
return image
}()
#objc func dismissPopup() {
DispatchQueue.global(qos: .userInitiated).async {
DispatchQueue.main.async {
self.dismiss(animated: true, completion: nil)
}
}
}
}
Your asynchronous code doesn't make sense. You dispatch onto a global queue and then immediately back onto the main thread. Try simply changing the implementation of dismissPopup() to this:
#objc func dismissPopup() {
dismiss(animated: true, completion: nil)
}

Resources