0

Overview
I'm trying tot understand app groups so that I can pass data and variables from my main app to my extension and viceversa.

What I found
It's very hard for me to understand a few concepts because all I could find were other SO questions that only showed how to store and retrieve data.
I even watched this tutorial (and read some more on medium) but I'm still confused.

What I'm doing
First of all I enabled app groups both in my container app and my app extension and i set the app group name to group.grop.

I have 3 files:

  1. Shared.swift
  2. KeyboardViewController
  3. ViewController

In my Shared.swift file I put the following code:

let sharedUserdefaults = UserDefaults(suiteName: SharedDefault.suitName)
struct SharedDefault {
    static let suitName = "group.grop"
    struct Keys{
        static let letters = "letters"
    }
}

Here the struct contains my suitName and the key.

Now, my keyboard extension looks like this:

enter image description here in my keyboardViewController, over the view did load, I put the following code:

    var lept: [Int] = sharedUserdefaults?.array(forKey: SharedDefault.Keys.letters) ?? []
    
    @IBOutlet weak var alabel: UILabel!
    @IBOutlet weak var blabel: UILabel!
    @IBOutlet weak var clabel: UILabel!
    
    @IBOutlet weak var abtn: UIButton!
    @IBOutlet weak var bbtn: UIButton!
    @IBOutlet weak var cbtn: UIButton!

inside of my viewDidLoad:

let nib = UINib(nibName: "keygrop", bundle: nil)
              let objects = nib.instantiate(withOwner: self, options: nil)
              view = objects[0] as? UIView

        
        sharedUserdefaults?.set(lept, forKey: SharedDefault.Keys.letters)
        guard let sharedWords = sharedUserdefaults?.array(forKey: SharedDefault.Keys.letters) else {return}
        print ("My words: \(sharedWords)")

below my viewDidLoad:

//I have one of these for every button.
 @IBAction func aaction(_ sender: Any) {
        
       lept.append(1)
        sharedUserdefaults?.set(lept, forKey: SharedDefault.Keys.letters)
       print(lept)
    }

In my ViewController I have another button named dbutton, two labels and this code inside of my view controller:

 guard let sharedWordss = sharedUserdefaults?.array(forKey: SharedDefault.Keys.letters) else {return}
        
        print ("My words: \(sharedWordss)")

Now what I want to happen is:

  1. The user presses a button from the keyboard.
  2. A number gets stored inside of an array.
  3. The user opens the app and if he presses the dbutton another value gets stored inside the array.
  4. A label displays what's inside the array and another one displays the number of the elements inside of it.

But using this method I can't access the lept variable from my ViewController. So I can't add anything to the array and I can't call lept.count, for example.

Question
How do I access (get the value/ add items/ edit...) a variable from a target in another target?
If you have anything I could use to take a better look into the subject, please send me the links!

crost
  • 165
  • 1
  • 13
  • You save an array of `Int` and then try to get an array of `String`s? You need to retrieve an array of `Int`. Your `guard` statement isn't passing through. – Starsky Sep 18 '20 at 13:36
  • It was a typo, I'm retrieving an array of int – crost Sep 18 '20 at 15:08
  • A keyboard extension does not communicate with the host app. The keyboard could appear in a different app, while your app might not even be running. They are independent of one another. That is why the only way to have them "talk" to each other is through saved information. – matt Sep 18 '20 at 15:21
  • @matt yeah I know they're indipendent. How do i save information? CoreData? – crost Sep 18 '20 at 17:45
  • matt wanted to tell you, that the communication doesn't happen instantly or reactively. You need to save it in one place, then get it from the sharedDefaults in another place. It is not a communication like delegates do, or callbacks, etc. – Starsky Sep 19 '20 at 13:59

1 Answers1

1
  1. Modify your lept to be a getter, and always get the latest value from the sharedDefaults:
var lept: [Int] {
    return sharedUserdefaults?.array(forKey: SharedDefault.Keys.letters) as? [Int] ?? [Int]()
}
  1. Inside the viewDidLoad for your keyboard extension, remove the code which saves the lept array to the sharedDefaults:

    sharedUserdefaults?.set(lept, forKey: SharedDefault.Keys.letters)

  2. Create a function which will do the same thing for each button (below I will write some optimizations regarding all this code):

func appendValue() {  
    var currentLept = self.lept
    currentLept.append(1)
    sharedUserdefaults?.set(currentLept, forKey: SharedDefault.Keys.letters)
   //print(currentLept) - you can print for debug purposes
}
  1. Call the function each time you press a button:
@IBAction func aaction(_ sender: Any) {
        
   appendValue()
}

This is the basic logic for sending any data from the main target to an extension.

Optimization hints

You should consider using a UICollectionView which will hold all your labels and buttons, and each cell would act as a button or label in your scenario. This way, you will create a custom UICollectionViewCell and implement everything just once, instead of handling each button separately.

As a rule of thumb, if you have anything which is repeating at least twice, it is either a tableView, if you need just vertical scrolling, or it should be a collectionView if you need horizontal scrolling, or cells which occupy only a portion of the screen's width.

Starsky
  • 1,829
  • 18
  • 25
  • As soon as I'll be on my mac I'll try this! Thank you so much for the optimization hints as well. Everything was much appreciated – crost Sep 18 '20 at 16:16
  • But what if I want to call lept in my ViewController? Right now lept is in the keyboard View controller – crost Sep 18 '20 at 17:44
  • And I have another question. right now if I want the user to remove an item from the array It says that I can't edit it. How do i make it eitable? – crost Sep 18 '20 at 18:13
  • The function `appendValue()` is a blueprint how you could modify the existing array in sharedDefaults. Firstly, you save it in a local variable, then do the changes on the local variable, then save it back to the sharedDefaults. Look closely what I did in the `appendValue()` function. – Starsky Sep 19 '20 at 13:57