I have an API that returns notifications if any activity in account. I am working first time with notifications. I am displaying these notifications in to UITableView. If user clicks on any notification from the table it redirects to the referral view and delete that notification from the Table list.
Now what I want is, if user leave the notification view with for example 4 notification listed and if 2 new notifications are added to the API then those 2 should have grey background colour and other 4 should have white background colour when user returns to the notificationView.
It is all coming from same API so I am very confuse how to accomplish this result. Its kind of Facebook notifications you can say. Do I need to make any changes to API side which can indicate me if any new notifications are added or is there anything else I am missing ? I know there is push notifications available but I am not using it here. Will it solve the issue if I use it? I am very confused. Please, any suggestion will be much appreciated.
Update: Here is my code :
struct UserNotification {
let id : Int?
let timeStamp : String?
let message : String?
init(json:[String:Any]) {
self.id = (json["Id"] as? Int)
self.timeStamp = (json["TimeStamp"] as? String)
self.message = (json["Message"] as? String)
}
}
var notificationsArray : [UserNotification] = []
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
self.FetchNotifications()
}
func FetchNotifications(){
URLSession.shared.dataTask(with: jsonUrlString!) { (data, response, error) in
guard let data = data else { return }
do {
if let jsonData = try JSONSerialization.jsonObject(with: data, options: .mutableContainers) as? [[String:Any]] {
self.notificationsArray.removeAll()
for notifications in jsonData {
let details = UserNotification(json: notifications)
self.notificationsArray.append(details)
}
}
} catch {
print(error.localizedDescription)
}
if (response as? HTTPURLResponse) != nil {
DispatchQueue.main.async {
self.notificationTableView.reloadData()
}
}
}.resume()
}
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let Cell = self.notificationTableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! CustomNotificationCell
// Cell.backgroundColor = UIColor(red: 245/255, green: 245/255, blue: 245/255, alpha: 1)
let temp = notificationsArray[indexPath.item]
// Setting id, time and message to labels
}
Well, since there is no API to support this, you cannot have this info cross device / multiscreen (if a user will open the notification in one device you will not be able to tell this this on another device without some other form communicating).
Need to save the info for a future app session
You can use UserDefaults.standard to save the state for a future session on the same device.
Create a notificationsStatus dictionary with the format [Id:read]. Read it when starting a new session and write in it the new updates statuses.
Save:
var notificationsStatus = ["101":true,"102":false]
let defaults:UserDefaults = UserDefaults.standard
defaults.set(notificationsStatus, forKey: "notifications")
Read:
notificationsStatus = defaults.value(forKey: "notifications")
and then use the read/unread to color the cells accordingly
Need to save the info for the same session
Use some structure where you save the state of a notification.
This can be done in multiple ways but the main idea is to create an object that doesn't get deallocated when leaving the controller and manipulate the date in it.
Related
I'm have a hard time creating a user setting options. I would like the user to customize the frequency of the timer to receive the local notifications. I'm using a switch on the SystemSettingsVC to for the user to select and set the user default and I'm using the user default setting in my MainVC for the TimerInterval. My app runs but the time doesnt change. I know that the switch is working because I'm also testing the background color change.
Here is my code for my SystemSettingsVC:
...
import UIKit
import SwiftUI
import CoreData
class SettingsViewController: UIViewController {
#IBOutlet weak var timeSelection: UISegmentedControl!
let userDefaults = UserDefaults.standard
let TIME_KEY = "TIME_KEY"
let ONE_HOUR_KEY = 60.0
let THREE_HOUR_KEY = 120.0
let SIX_HOUR_KEY = 300.0
override func viewDidLoad() {
super.viewDidLoad()
updateTime()
}
func updateTime() {
let time = userDefaults.object(forKey: "TIME_KEY")
if(time as? Double == ONE_HOUR_KEY) {
timeSelection.selectedSegmentIndex = 0
let userDefaults = UserDefaults.standard
userDefaults.set(60.0, forKey: "TIME_KEY")
view.backgroundColor = UIColor.white
save()
}
else if(time as? Double == THREE_HOUR_KEY) {
timeSelection.selectedSegmentIndex = 1
let userDefaults = UserDefaults.standard
userDefaults.set(120.0, forKey: "TIME_KEY")
view.backgroundColor = UIColor.gray
save()
}
else if(time as? Double == SIX_HOUR_KEY) {
timeSelection.selectedSegmentIndex = 2
let userDefaults = UserDefaults.standard
userDefaults.set(300.0, forKey: "TIME_KEY")
view.backgroundColor = UIColor.darkGray
save()
}
}
func save() {
if let savedData = try? NSKeyedArchiver.archivedData(withRootObject: clock, requiringSecureCoding: false){
let defaults = UserDefaults.standard
defaults.set(savedData, forKey: "TIME_KEY")
}
}
#IBAction func selectTimeOfQuotes(_ sender: Any) {
switch timeSelection.selectedSegmentIndex
{
case 0:
userDefaults.set(60.0, forKey: "TIME_KEY")
save()
case 1:
userDefaults.set(120.0, forKey: "TIME_KEY")
save()
case 2:
userDefaults.set(300.0, forKey: "TIME_KEY")
save()
default:
userDefaults.set(60.0, forKey: "TIME_KEY")
save()
}
updateTime()
}
}
...
Here is the code for my view controller to where I call the user defaults, I placed let userDefaults = UserDefaults.standard in my ViewDidLoad :
'''Code''' ```
func configureAlerts() {
let center = UNUserNotificationCenter.current()
center.removeAllDeliveredNotifications()
center.removeAllPendingNotificationRequests()
let listQuotes = quotes
let i = 1
let content = UNMutableNotificationContent()
content.title = “Inspire”
content.body = listQuotes[i].shareMessage
content.sound = UNNotificationSound.default
let alertDate = Date().byAdding(days: i)
var alertComponents = Calendar.current.dateComponents([.day, .month, .year], from: alertDate)
alertComponents.hour = 8
let userDefaults = UserDefaults.standard
typealias NSTimeInterval = Double
let thisTime:TimeInterval = userDefaults.double(forKey: "TIME_KEY")
let trigger = UNTimeIntervalNotificationTrigger(timeInterval: thisTime, repeats: true)
let uuidString = UUID().uuidString
let request = UNNotificationRequest(identifier: uuidString, content: content, trigger: trigger)
center.add(request) { error in
if let error = error {
print(error.localizedDescription)
}
}
You are not showing how your Models are connected so we can't tell where the miscommunication is happening or maybe that is the issue. They are not connected.
But at a simple glance you are not rescheduling the notifications. selectTimeOfQuotes, save or updateTime do not call configureAlerts.
Something to note you have a lot of repeating code and hardcoded values that could be the source of the confusion.
BTW 120 is 2 hours not 3 idk if that is on purpose but it highlights my next point.
When you change a value you only want to do it in 1 place; if possible; so centralizing the models will help you avoid having to change things in multiple places.
For the options for your picker an enum can hold everything.
enum NotificationInterval: Double, CaseIterable, Codable{
case ONE_HOUR_KEY = 3660 //TimeInterval == seconds
case THREE_HOUR_KEY = 10800 //TimeInterval == seconds
case SIX_HOUR_KEY = 21600 //TimeInterval == seconds
func label() -> String{
var result = ""
switch self {
case .ONE_HOUR_KEY:
result = "1 hour"
case .THREE_HOUR_KEY:
result = "3 hours"
case .SIX_HOUR_KEY:
result = "6 hours"
}
return result
}
func color() -> UIColor{
var result = UIColor.label
switch self {
case .ONE_HOUR_KEY:
result = UIColor.white
case .THREE_HOUR_KEY:
result = UIColor.gray
case .SIX_HOUR_KEY:
result = UIColor.darkGray
}
return result
}
///Key for storage of user selected interval
static var userDefaultKey: String{
"TIME_KEY"
}
///Saves value to store using the `userDefaultKey`
func saveToStore(){
var mgr = UserDefaultManager()
mgr.intervalTime = self
}
///Gets value from store using the `userDefaultKey`
static func getFromStore() -> NotificationInterval{
let raw = UserDefaultManager().intervalTime
return raw
}
///Gets the index for the object in the `allCases` array
func getAllCasesIndex() -> Int?{
NotificationInterval.allCases.firstIndex(where: {
self == $0
})
}
///Gets the index for the `userDefaultKey` stored object in the `allCases` array
static func getStoredIndex() -> Int?{
NotificationInterval.getFromStore().getAllCasesIndex()
}
}
Then since you have at least 2 unrelated classes that use the value store in user defaults you can centralize that work too
///This stores and retreives userdefaults to a predetermined store
struct UserDefaultManager{
//Having a single location for this will simplify UserDefault storage
//A use case would be switching to an App Group store when you decide to support watch in the future or if you want to add Widgets
private let store = UserDefaults.standard
///User selected interval for the notifications
var intervalTime: NotificationInterval{
get{
getObject(forKey: NotificationInterval.userDefaultKey, type: NotificationInterval.self) ?? NotificationInterval.ONE_HOUR_KEY
}
set{
save(newValue, forKey: NotificationInterval.userDefaultKey)
}
}
///Saves any Codable to UserDefaults
func save<T: Codable>(_ object: T, forKey: String){
let encoder = JSONEncoder()
do{
let encoded = try encoder.encode(object)
store.set(encoded, forKey: forKey)
}catch{
print(error)
}
}
//Gets any Codable from UserDefaults
func getObject<T: Codable>(forKey: String, type: T.Type) -> T?{
guard let saved = store.object(forKey: forKey) as? Data else {
return nil
}
let decoder = JSONDecoder()
do{
let loaded = try decoder.decode(T.self, from: saved)
return loaded
}catch{
print(error)
return nil
}
}
}
Then your SettingsViewController will look like this
class SettingsViewController: UIViewController {
///Programatic use of IBOutlet
var timeSelection: UISegmentedControl!
private let quoteManager = QuoteManager()
override func viewDidLoad() {
super.viewDidLoad()
//Create control PS I dont have a storyboard setup but you can replace this with your IBOutlet and IBAction
timeSelection = UISegmentedControl(items: NotificationInterval.allCases.map({
$0.label()
}))
timeSelection.addTarget(self, action: #selector(selectTimeOfQuotes), for: .allEvents)
//Set the initial value from storage
timeSelection.selectedSegmentIndex = NotificationInterval.getStoredIndex() ?? 0
self.view.addSubview(timeSelection)
timeSelection.translatesAutoresizingMaskIntoConstraints = false
timeSelection.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
timeSelection.centerYAnchor.constraint(equalTo: view.centerYAnchor).isActive = true
//End of programatic setup
//Set the color from storage
view.backgroundColor = NotificationInterval.getFromStore().color()
}
///Programatic use of IBAction
#objc
func selectTimeOfQuotes() {
//Identify the selected interval
let interval = NotificationInterval.allCases[timeSelection.selectedSegmentIndex]
//Save it
interval.saveToStore()
//Change the color
view.backgroundColor = interval.color()
//Change the notification
quoteManager.rescheduleQuotes()
}
}
As the last line of code shows once all the work is done you should reschedule the quotes.
I created a mini-QuoteManager since you do not show this connection. This manager can be used by any View Controller to get the quotes and maybe even reschedule when the quotes change by calling the provided method.
//Adapt this to your use case this is just a sample
///Liason for quote Storege
struct QuoteManager{
var listQuotes = ["one", "two", "three"]
private let notificationManager = NotificationManager.shared
private let userDefaultsManager = UserDefaultManager()
///Reschedules quotes
func rescheduleQuotes(count: Int = 10){
let title = "Inspire"
notificationManager.deleteNotifications()
print(#function)
for n in 1..<count+1{
print(n)
let newDate = userDefaultsManager.intervalTime.rawValue*Double(n)
//Idenfier must be unique so I added the n
notificationManager.scheduleUNTimeIntervalNotificationTrigger(title: title, body: listQuotes.randomElement()!, timeInterval: newDate, identifier: "com.yourCompany.AppName.\(title)_\(n.description)")
}
}
}
The QuoteManager calls the NotificationManager. I created a small version below.
class NotificationManager: NSObject, UNUserNotificationCenterDelegate{
//Singleton is requierd because of delegate
static let shared: NotificationManager = NotificationManager()
let notificationCenter = UNUserNotificationCenter.current()
private override init(){
super.init()
//This assigns the delegate
notificationCenter.delegate = self
requestAuthorization()
}
func scheduleUNTimeIntervalNotificationTrigger(title: String, body: String, timeInterval: TimeInterval, identifier: String, repeats: Bool = false){
print(#function)
let content = UNMutableNotificationContent()
content.title = title
content.body = body
content.sound = .default
let trigger = UNTimeIntervalNotificationTrigger(timeInterval: timeInterval, repeats: repeats)
let request = UNNotificationRequest(identifier: identifier, content: content, trigger: trigger)
notificationCenter.add(request) { (error) in
if error != nil {
print(error!)
}
self.printNotifications()
}
}
func requestAuthorization() {
print(#function)
notificationCenter.requestAuthorization(options: [.alert, .badge, .sound]) { (granted, error) in
if granted {
print("Access Granted!")
} else {
print("Access Not Granted")
}
}
}
func deleteNotifications(){
print(#function)
notificationCenter.removeAllPendingNotificationRequests()
notificationCenter.removeAllDeliveredNotifications()
}
///Prints to console schduled notifications
func printNotifications(){
print(#function)
notificationCenter.getPendingNotificationRequests { request in
print("UNTimeIntervalNotificationTrigger Pending Notification")
for req in request{
if req.trigger is UNTimeIntervalNotificationTrigger{
print((req.trigger as! UNTimeIntervalNotificationTrigger).nextTriggerDate()?.description ?? "invalid next trigger date")
print(req.content.body)
}
}
print("UNCalendarNotificationTrigger Pending Notification")
for req in request{
if req.trigger is UNCalendarNotificationTrigger{
print((req.trigger as! UNCalendarNotificationTrigger).nextTriggerDate()?.description ?? "invalid next trigger date")
}
}
}
}
//MARK: UNUserNotificationCenterDelegate
func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: #escaping (UNNotificationPresentationOptions) -> Void) {
completionHandler(.banner)
}
}
It might seem like a lot but if you focus on the SettingsViewController you will see how much simpler the whole thing becomes.
All this is working code. Just copy and paste into a .swift file.
You might have to change the UISegmentedControl since I created it programmatically but if you put the SettingsViewController in a blank storyboard it should work as is.
I am trying to implement a UICollectionViewDiffableDataSource for my collectionView. My code compiles fine, however I keep running into this error the first time I apply a snapshot to it, with the following error:
Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'Invalid parameter not satisfying: self.supplementaryViewProvider || (self.supplementaryReuseIdentifierProvider && self.supplementaryViewConfigurationHandler)'
Here is my code:
var groups: [Group] = [Group]()
var dataSource: UICollectionViewDiffableDataSource<Section, Group>!
// MARK: - View Life Cycle
override func viewDidLoad() {
super.viewDidLoad()
self.searchBar.delegate = self
self.groups = DummyData.groups
setupDataSource()
}
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
performSearch(searchQuery: nil)
}
// MARK: - Helper Functions
func performSearch(searchQuery: String?) {
let filteredGroups: [Group]
if let searchQuery = searchQuery, !searchQuery.isEmpty {
filteredGroups = groups.filter { $0.contains(query: searchQuery) }
} else {
filteredGroups = groups
}
var snapshot = NSDiffableDataSourceSnapshot<Section, Group>()
snapshot.appendSections([.main])
snapshot.appendItems(filteredGroups, toSection: .main)
dataSource.apply(snapshot, animatingDifferences: true, completion: nil)
}
func setupDataSource() {
dataSource = UICollectionViewDiffableDataSource <Section, Group>(collectionView: collectionView) { (collectionView: UICollectionView, indexPath: IndexPath, group: Group) -> UICollectionViewCell? in
guard let cell = self.collectionView.dequeueReusableCell(
withReuseIdentifier: String(describing: MyGroupsCollectionViewCell.self), for: indexPath) as? MyGroupsCollectionViewCell else {
fatalError("Cannot create new cell") }
cell.configure(withGroup: group)
return cell
}
}
If needed, I can post the full call stack.
Found the answer. I was using the storyboard to create my collectionView and accidentally had the attribute for Section Header set to true. Because of this, the collectionView needed to pull the view for the section header for somewhere, but I never told it where, hence the
parameter not satisfying: self.supplementaryViewProvider || (self.supplementaryReuseIdentifierProvider && self.supplementaryViewConfigurationHandler)
Here's a good article I found on it for anyone in the future who runs into this issue:
https://medium.com/#jamesrochabrun/uicollectionviewdiffabledatasource-and-decodable-step-by-step-6b727dd2485
I have a project that I have built where I am trying to include the sinch framework for making SMS verification. I added Sinch to the project VIA cocoapods, and also by manually adding the folder/framework to my xcode file system.
The problem i'm having right now is that my version of the CountrySelectionViewController.swift cannot access the SinRegionInfo protocol defined inside of the Sinch framework... i'm not sure what is going wrong. An example of the code/error inside CountrySelectionViewController.swift is here:
var entries: Array<SINRegionInfo> = []; ---> Use of undeclared type 'SinRegionInfo'
The strange part is that everything seems to be the same in my project as it is in the sample project, but in the sample project, there is no problem accessing the protocol.
CountrySelectionViewController.swift
import UIKit
import SinchVerification
class CountrySelectionViewController : UITableViewController {
var isoCountryCode: String?
var onCompletion: ((String) -> Void)?
var entries: Array<SINRegionInfo> = [];
override func viewDidLoad() {
super.viewDidLoad();
let regionList = PhoneNumberUtil().regionList(forLocale: Locale.current);
entries = regionList.entries.sorted(by: { (a: SINRegionInfo, b: SINRegionInfo) -> Bool in
return a.countryDisplayName < b.countryDisplayName;
})
}
override func viewWillAppear(_ animated: Bool) {
let row = entries.index { (region: SINRegionInfo) -> Bool in
return region.isoCountryCode == isoCountryCode;
}
if row != nil {
tableView.selectRow(at: IndexPath.init(row: Int(row!), section: 0), animated: animated, scrollPosition: .middle);
}
}
I'm testing with an iPhone 5 in Swift 2.0, Xcode 7.1 and iOS 9.1 with a good wifi connection.
I have followed this tutorial ( http://www.appcoda.com/google-sign-in-how-to/ ) and everything works fine on simulator but when I run this app on a real device using my iPhone 5 it opens the Google search App (with some registered accounts inside them) for handle sign in. It prompts the user to select an account. Once an account is selected, the google search app then asks the user if my app can access their information. Once a user clicks SIGN IN,
After, when come back on the app code don't enter on this function:
func signIn(signIn: GIDSignIn!, didSignInForUser user: GIDGoogleUser!, withError error: NSError!) {
if let err = error {
print(err)
}
else {
performSegueWithIdentifier("idSegueContent", sender: self)
}
}
My main ViewController() class is this:
import UIKit
class ViewController: UIViewController, GIDSignInDelegate, GIDSignInUIDelegate {
#IBOutlet weak var signInButton: GIDSignInButton!
var contentViewController: ContentViewController!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
GIDSignIn.sharedInstance().delegate = self
GIDSignIn.sharedInstance().uiDelegate = self
GIDSignIn.sharedInstance().clientID = "MY_CLIENT_ID"
GIDSignIn.sharedInstance().scopes.append("https://www.googleapis.com/auth/plus.login")
GIDSignIn.sharedInstance().scopes.append("https://www.googleapis.com/auth/plus.me")
GIDSignIn.sharedInstance().signInSilently()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
// MARK: Google SignIn Delegate Methods
func signIn(signIn: GIDSignIn!, didSignInForUser user: GIDGoogleUser!, withError error: NSError!) {
if let err = error {
print(err)
}
else {
performSegueWithIdentifier("idSegueContent", sender: self)
}
}
func signIn(signIn: GIDSignIn!, didDisconnectWithUser user: GIDGoogleUser!, withError error: NSError!) {
if let err = error {
print(err)
}
contentViewController.dismissViewControllerAnimated(true, completion: nil)
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == "idSegueContent" {
contentViewController = segue.destinationViewController as! ContentViewController
}
}
}
If the Google search app is not installed, then Safari opens in the app just fine and once signed in, the delegate callback methods work just as expected.
I had the same issue and finally got it working after restarting my phone. (After hours of tests, checks, and re-organizing code!) Hopefully this simple solution saves someone else from the trouble.
I know that theoretically it's possible to create multiple instances of the same class with a property that would have a different value for each instance.
The thing is, I can't make it happen.
Each time I'm creating a new instance, it gets the property's value of the other instances, and when I'm changing one value for an instance, it changes the other's too.
So my guess is that I'm doing something wrong (obviously), like accessing the class property value instead of the instance property value... Here's the code.
class CustomUIImageView: UIImageView {
var someParameter: Bool = false // This is the property I want to be different in each version of the instance.
}
class ClassSiege: UIViewController, UIGestureRecognizerDelegate {
var myView: CustomUIImageView! //the instance declaration.
// I use this gesture recognizer to find out the value of the instance I'm tapping on.
func handleTap (sender: UITapGestureRecognizer) {
print("value of someParameter \(self.myView.someParameter)")
}
func handlePan(recognizer: UIPanGestureRecognizer) {
let iv: UIView! = recognizer.view
let translation = recognizer.translationInView(self.view)
iv.center.x += translation.x
iv.center.y += translation.y
recognizer.setTranslation(CGPointZero, inView: self.view)
var centerBoardX = BlackBoard.center.x // 'Blackboard' is a fixed image on the screen.
var centerBoardY = BlackBoard.center.y
var centerRondX = iv.center.x
var centerRondY = iv.center.y
if centerRondY - centerBoardY < 100 {
self.myView.someParameter = true // If the distance between myView and the blackboard is under 100 I want the instance's property to become true.
} else {
self.myView.someParameter = false // On the other hand, if the distance is greater than 100, I want it to be false.
}
}
// When the user pushes a button, it triggers this method that creates a new instance of myView and add it to the screen.
#IBAction func showContent(sender: AnyObject) {
// some code...
// Here I'm creating the instance of the view and I give it the gesture recognizer parameters. I don't think that relevant to the issue, so I'm not adding the code.
}
}
So clearly that's not the good way to do it, but what's wrong, and how can it be solved?
Basing my answer on your related question.
If what you want to achieve is initializing a property with a value that you provide, just add a new parameter to the initializer. If for instance you are using the initializer with a CGRect passed in, then you can implement an initializer like this:
class CustomUIImageView : UIImageView {
let someParameter : Bool
required init(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
init(frame: CGRect, someParameter: Bool) {
self.someParameter = someParameter
super.init(frame: frame)
}
}
I hope that this is what you are looking for - let me know otherwise.
I've found the solution, and if you've been facing the same issu, here's how to deal with it.
The secret is to downcast the recognizer.view to take the parameter of the subclass CustomUIImageView.
here's how :
func handleTap (sender: UITapGestureRecognizer) {
println("value of someParameter \(self.myView.someParameter)") //I use this gesture recognizer to find out the value of the instance I'm tapping on.
}
func handlePan(recognizer:UIPanGestureRecognizer) {
let iv : UIView! = recognizer.view
let translation = recognizer.translationInView(self.view)
iv.center.x += translation.x
iv.center.y += translation.y
recognizer.setTranslation(CGPointZero, inView: self.view)
var centerBoardX = BlackBoard.center.x //blackboard is a fixed image on the screen.
var centerBoardY = BlackBoard.center.y
var centerRondX = iv.center.x
var centerRondY = iv.center.y
var myParameter = recognizer.view as CustomUIImageView //<- this is the key point. Downcasting let you access the custom subclass parameters of the object that is currently moved
if centerRondY - centerBoardY < 100 {
myParameter.someParameter = true //so now I'm really changing the parameter's value inside the object rather than changing a global var like I did before.
} else {
myParameter.someParameter = false
}
}
//when user pushes a button, it triggers this func that creates a new instance of myView and add it to the screen.
#IBAction func showContent(sender: AnyObject) {
some code...
//here I'm creating the instance of the view and I give it the gesture recognizer parameters. I don't think that relevant to the issue, so I'm not adding the code.
}