Swift How to fix errors with Target Membership? - ios

I am beginner to Swift and I am not aware of all the little details, so please forgive if it's a stupid question
My app is in quite advanced stage of development, so I would like to not mess with the existing code as little as possible. My problem is that I want to implement Today Extension in my app, in it I want to display a tableView that will display data from a single array from my "Plum" class and I need one method from the class to handle the selection. Unfortunately when I change the Plum's target membership to TodayExtension a whole bunch of errors are shown because many APIs from that class aren't available to TodayExtension. The class inherits from AVAudioPlayer so most essential methods aren't available in Extension.
I tried to create a helper class that would get the array from Plum and return it in method to my TableView but that still doesn't work because of "Use of unresolved identifier 'Plum'"
How can I obtain the array and use the method?

I think while adding Today Extension you might have got some classes for today extension,
You can use App Group with User Defaults functionality to transfer data from iOS app to today Extension classes
1) To set data you can use
var defaults: NSUserDefaults = NSUserDefaults(suiteName: <GroupID>)!
defaults.setObject(<YourArray, forKey:<KeyName>)
2) In Today Extension target's Class you can fetch that array like this
var defaults: NSUserDefaults = NSUserDefaults(suiteName: <GroupID>)!
var <YourArray> = defaults.stringForKey(<KeyName>)
Note : This is just pseudo code might contain error

Adding the Plum class in the today extension is a bad idea. Extensions should be lightweight and you only need to transfer the data needed.
In your case you may need the array of title and description. So form a array of dictionary with needed details and store these details in App group user defaults like #Hitesh answer.
In your today extension class, read this array from the user defaults then display the details in the table view.

Related

Should I use NSUserDefault, dictionaries, core data - or something else?

I'm having some issues with the app, that I'm making, which I thought would be a lot easier to explain with some photos, so ... :
Ofcourse the "Create New Person-button" in nr. 1 leads you to number two.
Now, I'm having issues figuring out how to save this data about the person in the "People Diary". The goal is, that when you enter a person's name, add a photo (an enable-camera feature, I will struggle with at a later time...) and add an answer to the question - then you only need to press "Save this person", and then you will be redirected to the AllPersonsInYourDiaryViewController, where there is now a new tableViewCell with this new person's name (maybe with a subtitle containing the answer and the photo shown in miniature in the cell too).
(Naturally you can then enter this cell with the data about the person too - but that comes next.)
So far in the app, I have used NSUserDefault, when allowing the user to create this specifik Diary by the Name "Antons Diary" with the specifik question and so on. But now it came to my attention, that maybe it is smarter to use something else? I tried with dictionaries, but couldn't get this to work properly.
So...: Before I spend hours and hours playing around with one of these ways, will someone smarter than me, tell me what the best approach would be?
If I can give my two cents, the first thing you have to do is to “design” how to represent a person programmatically. You can create a struct or class to do so, even though a struct is more suitable:
struct Person {
var name: String?
var answer: String?
var photo: String?
}
Then you can decide how to save the data of such an object persistently. If you want to use a database, then I would recommend using SQLite with FMDB library. It’s really easy and fast to learn how to use it, and it's also quite handy. I've used it big projects and it works smoothly. I find CoreData too complicated and an overkill based on what you need.
If you don’t want to use a database, your only other way is to save to files, but still, you’ve got options here too. If you encode (see Codable protocol in Swift), you can use NSKeyedArchiver to convert to Data object and write then to disk. If you like using dictionaries, and since the properties you’re going to have for a person are not going to be too many, you could create a dictionary by assigning the properties and their values, and then convert and save as JSON data, or even Plist files. Without any intension to do promotion here, but just to provide some additional help, if you want take a look to a library that I’ve written and that can do all these automatically for you. It’s a protocol that you have to adopt, and then you can instantly convert your struct to a dictionary, JSON or plist and save to files.
No matter which way you’re going to select, save the images as single files to documents directory, and keep their file names only stored to database/file. Based on them, you can build the path to each image (or the URL) easily when needed. Warning: Do not save the full path to the documents directory, especially if you’re testing on Simulator; paths are changing on each build. Save the file name only.
Additionally, if you’re going to use a struct like the one shown above, you could implement small but super convenient functions that will be responsible for saving, loading, or updating your data to the solution (database/file) you’ll eventually select. That way, you’ll have related stuff gathered in one place, and easily accessible (i.e., person.save()).
struct Person {
var name: String?
var answer: String?
var photo: String?
func save() {
…
}
func load() {
…
}
// More functions…
}
Lastly, avoid using UserDefaults, or at least keep just a few non-critical data there. UserDefaults are not meant to keep all data produced by your app. Most importantly, do not use it for saving sensitive data, especially passwords or other stuff like that.
I hope the above will help you make your mind.
I can give you the logic behind coreData and NSUserDefaults, but you will decide which one should be used.
CoreData is usually used as a database. you can create entities and attributes for every entity. Moreover, you can create relations between these entities.
When extracting data from coreData, you can arrange this data using NSSortDescriptor or select a specific record using NSPredicate.
So as you can see CoreData is a database.
While NSUserDefaults is usually used to save a password, username, userID... and such issues that you will regularly use in the app. NSUserDefaults gives you a direct access to the saved variables at any time. However, CoreData will take more time and lines of code to access the entity and make the query.
Now, check which method suits your case more.

Swift Firebase viewcontroller only for specific user

In my app I have to validate user generated content, to do that I saw that with the panel of Firebase is not a fast thing, so I searched and I found Firebase FireAdmin, but it's not free and what I want is only change a value of approvation from not to yes (after have seeing content).
It's a good idea to make a viewcontroller hide for all exept from me by checking firauth property of Firebase?
let userID : String = (Auth.auth().currentUser?.uid)!
if userID == myid... { show view controller...
Thanx in advance
No it's not a good idea. This value can be changed or the controller can be access if your code is usafe. The application will be heavier for a controller that will not be used by users.
You have to build an admin interface if you don't want to pay for FirebaseAdmin.
In function of what you are looking for, you can also have a look at Firebase Database where you can read and edit values.

Object reference not set to an instance of an object in xamarin ios app group

I am trying to build today widget in Xamarin.
In the simulator everything works, but when I run it on real device my widget crashes with the following exception:
object reference not set to an instance of an object.
My code is:
var defs = new NSUserDefaults("group.com.gto.extension", NSUserDefaultsType.SuiteName);
defs.Synchronize();
var equities = defs.ValueForKey(new NSString("key1"));--> this row crashes my widget.
There is a difference in-between trying to access the NSUserDefaults for a single application or a group hereof. The latter is what you are currently trying to achieve. I will try to summaries the difference between the two strategies in this answer.
App Group User Defaults
I assume you're trying to read an entry from the NSUserDefaults from another application or extension you have made? Only in that case it is sensible to use the NSUserDefaults of the given. If so, you need to ensure the following:
First, you will need to ensure that the App Group and the required App IDs have been properly configured in the Certificates, Identifiers & Profiles section on iOS Dev Center and have been installed on in the development environment.
Next, your App and/or Extension projects will need to be one of the valid App IDs created above, that the Entitlements.plist file has the App Groups enabled and specified and that it get's included in the App Bundle.
With this all in place, the shared App Group user Defaults can be accessed [...]
https://developer.xamarin.com/guides/ios/application_fundamentals/user-defaults/#Accessing_an_App_Group_NSUserDefaults_Instance
The two points mentioned above may be the reason to why your application is crashing.
Single-application User Defaults
If on the other hand you only need to access a value from the NSUserDefaults of the current application, you can simply do as follows:
var defs = NSUserDefaults.StandardUserDefaults;
Reading the values
To read values from the NSUserDefaults, as seen in the guide and documentation, you should do as follows:
var boolForKey = defs.BoolForKey("key");
var stringForKey = defs.StringForKey("key");
....
Where "key" parameter is the key for the value you previously stored in your NSUserDefaults dictionary.
It would most likely also be sensible to surround any calls to retrieve values from the NSUserDefaults in a try/catch. The key may not yet exist in the NSUserDefaults, which is most likely the issue in your case.

How do I save a var when my iOS app closes? [duplicate]

This question already has answers here:
How to save local data in a Swift app?
(12 answers)
Closed 6 years ago.
In total I have 2 viewcontrolers. The App is the same like this guy made in a tutorial. https://www.youtube.com/watch?v=LrCqXmHenJY&t=40s
To make a start, I made a var:
import UIKit
var list = ["Task 1", "Task 2", "Task 3", "Task 4"]
class FirstViewController: UIViewController , UITableViewDelegate, UITableViewDataSource{
My current problem is, that when I close the app no ToDo's which I created were saved.
What do I need to do to save my var list so that my ToDo-List isn't empty when I open it for the next time?
You can use UserDefaults to save/load application state or configurations. For complex requirements use CoreData
Writing/Saving before app termination
let defaults = UserDefaults.standard
defaults.set(true, forKey: "Enabled")
Reading/Loading on app launch
let defaults = UserDefaults.standard
let enabled = defaults.bool(forKey: "Enabled")
Read the related Apple docs here.
If you want an easy way to store a list of strings, you can use UserDefaults. Another way to do this is to use Core Data which is more difficult to use. It is usually used to store more complex data structures than an array of strings.
To save the string array to UserDefaults, do this:
UserDefaults.standard.set(list, "myStringArray")
You can replace "myStringArray" with any key you want.
To retrieve it, do this:
list = UserDefaults.standard.stringArray(forKey: "myStringArray")
I suggest you save the array in this method in App Delegate:
func applicationDidEnterBackground(_ application: UIApplication) {
}
For more info on User Defaults, see https://developer.apple.com/reference/foundation/userdefaults
You have very simple needs. Look at NSUserDefaults (now called UserDefaults in Swift 3.)
Save your data to UserDefaults when it changes, and read it back when you display your view controller.
As Eric says in his comments, make list an instance variable of your view controller.
EDIT:
In the comments below, rmaddy pointed out that the app will be saving a to-do list. That will likely grow in complexity from an array of a handful of items to a larger array or potentially a more complex structure.
Given that, you might want to look at saving your data to a plist file in the documents directory (quite simple) or using NSCoding if you have custom objects other than the small list of "property list" types that can be saved to a plist.
Both of those solutions read and write the data all at once to a file. That might be ok for a to-do list app.
If you need to change parts of a larger data-set and leave the rest unchanged then it's time to consider a database like Core Data.

Using NSUserDefaults to share data to watchkit

I am trying to use NSUserDefaults to share my data with the WatchKit files. I am trying to have it so when the button function is executed the watchLabel.setText to data from an array. The array and function that selects the data was created in the iOS application. (Unfortunately many resources I come across are in objective-C or extremely vague.)
I have set up app groups for both iOS and Watchkit
In my iOS Swift file I am trying to share my array(arrayBook) and function(.randomData) to use with the WatchKit controller. PS: I have no compiler errors.
let sharedDefaults = NSUserDefaults(suiteName: "group.applewatchtest")
sharedDefaults?.arrayForKey(arrayBook.randomData())
sharedDefaults?.synchronize()
Watchkit Controller; Unsure the correct syntax for fetching data and setting the label to random string from the array. - This is within the UIButton func.
let sharedDefaults = NSUserDefaults(suiteName: "group.applewatchtest")
let sharedArray = sharedDefaults?.arrayForKey("Shared")
watchLabel.setText(arrayBook.randomData())
Where am I going wrong when fetching the data to set the label to data from the array which is stored in my iOS application.
sharedDefaults?.arrayForKey(arrayBook.randomData())
This line of code is not doing anything. You're reading the array from defaults, using a key of whatever arrayBook.randomData() returns, and doing nothing with it.
I assume you want something like
sharedDefaults?.setObject(arrayBook, forKey:"Shared")
Which will write that array into defaults. You then get it back out in the watch (which looks fine) and get a random value using randomData().

Resources