Programmatically remove contact from adress book on specific time in swift [closed] - ios

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 6 years ago.
Improve this question
I am trying to programmatically remove contacts from address book on specific time. Is it even possible in Swift and do Apple allow it?. I'm already familiar with CNContactStorebecause I have got working adding contacts into phonebook. Granted access into Contacts etc.. But I do not know how to programmatically delete contacts from addressbook(forever) on specific time.
Any help is appreciated!

REFERENCE:
http://www.ios-blog.co.uk/tutorials/swift/contacts-framework-p2/
EXPLANATION (FROM THE LINK):
Delete Contact
"The iOS contacts framework gives us the function deleteContact(:) to help us delete contacts. Hopefully you’ve understood this tutorial enough so far to proceed as I’m only going to outline the process and let you have a try. Just like we have throughout this tutorial we are going to instantiate an object of type CNSaveRequest, Issue the deleteContact(:) function that I just mentioned and pass the mutable contact to it. Then, Like when we created contacts or updated contacts we are going to use the executeSaveRequest(_:).
Please note that Delete means Delete! Contacts that are deleted can not be obtained again. This shouldn’t matter too much on the simulator but you do need to make sure that you have safety protocols in place so that you don’t delete a users contacts.
So, Did you manage to get the delete working? Ok, Fine, I will post the full code so you can see."
SOLUTION (FROM THE LINK):
let predicate = CNContact.predicateForContactsMatchingName("John")
let toFetch = [CNContactEmailAddressesKey]
do{
let contacts = try store.unifiedContactsMatchingPredicate(predicate,keysToFetch: toFetch)
guard contacts.count > 0 else{
print("No contacts found")
return
}
guard let contact = contacts.first else{
return
}
let req = CNSaveRequest()
let mutableContact = contact.mutableCopy() as! CNMutableContact
req.deleteContact(mutableContact)
do{
try store.executeSaveRequest(req)
print("Success, You deleted the user")
} catch let e{
print("Error = \(e)")
}
} catch let err{
print(err)
}

Related

firestore collection path giving bugs with constants value and String value

So my goal is to get rid of these bugs completely. I am in a dilemma where each decision leads to a bug.
The first thing I can do that eventually becomes an issue is use a String-interpolated collection path in all my query functions like so:
func getEventName() {
listener = db.collection("school_users/\(user?.uid)/events").order(by: "time_created", descending: true).addSnapshotListener(includeMetadataChanges: true) { (querySnapshot, error) in
if let error = error {
print("There was an error fetching the data: \(error)")
} else {
self.events = querySnapshot!.documents.map { document in
return EventName(eventName: (document.get("event_name") as! String))
}
self.tableView.reloadData()
}
}
}
The thing with this is, when I run the app on the simulator, I am restricted from pressing buttons and then sometimes I can press them and then sometimes they get restricted again. This bug is so confusing because it makes no sense where it springs from.
The other issue is I can use a Constants value in all the query functions in my collections path.
static let schoolCollectionName = "school_users/\(user?.uid)/events"
This is nested in a Firebase struct within the Constants struct. In order to keep Xcode from giving errors I create a let users = Auth.auth().currentUser variable outside the Constants struct. The issue with this value is that when I put that in all of my query functions collection paths, all the buttons are accessible and selectable all the time, but when a user logs out and I log in as a new user, the previous user's data shows up in the new user's tableview.
It would obviously make more sense to use the Constants value because you prevent typos in the future, but I can't figure out how to get rid of the bug where the old user's data shows up in the new user's tableview. Thanks in advance.
The user id should definitely not be a constant. What it sounds like is that right now, you have no reliable way to change users -- your setup probably depends on which user is logged in at app startup, since that's where your variable gets set.
I would do something more like this:
func getEventName() {
guard let user = Auth.auth().currentUser else {
//handle the fact that you don't have a user here -- don't go on to the next query
return
}
listener = db.collection("school_users/\(user.uid)/events").order(by: "time_created", descending: true).addSnapshotListener(includeMetadataChanges: true) { (querySnapshot, error) in
Note that now, user.uid in the interpolated path doesn't have the ? for optionally unwrapping it (which Xcode is giving you a warning for right now). It will also guarantee that the correct query is always made with the currently-logged-in user.
Regarding being able to press the buttons, that sounds like an unrelated issue. You could run your app in Instruments and check the Time Profiler to see if you have long-running tasks that are gumming up the main/UI thread.

Does simply pulling all users from firebase database and putting them into an array efficient?

I have a simple iOS app that part of the app grabs all the users from firebase database so you can search them, and do different functions. Now my question is, if/when the app grows and there are thousands of users, does pulling all the users from the database and adding them to an array of [user]'s, still not crash or slow the app? I see so many people on youtube just loop through firebase and grab all the users. Please note I am excluding profile photos so there is no downloading images involved, just strings. I have some code I thought could solve this possible problem, but I am starting to wonder if there even is a problem with just fetching all the users from firebase and putting them into and array and then displayed in a tableview.
Here is some of my code right now, but it still I notice when I type in one letter, then turn airplane mode on, it downloaded all the users. I really need some help or some advice on this one, thanks.
var checklers = [String]()
func updateSearchResults(for searchController: UISearchController) {
if searchController.searchBar.text == "" {
filteredUsers = users
}
else {
print("refreshing")
if let uidi = FIRAuth.auth()?.currentUser?.uid {
view.addSubview(activityInd)
activityInd.startAnimating()
filteredUsers.removeAll()
checklers.removeAll()
let ref = FIRDatabase.database().reference()
ref.child("users").queryOrderedByKey().observe(.value, with: { snapshot in
if let userr = snapshot.value as? [String : AnyObject] {
for (_, velt) in userr {
if let usernamerr = velt["Username"] as? String {
if usernamerr.lowercased().contains(searchController.searchBar.text!.lowercased()) {
let userNew = usera()
if let name = velt["Full Name"] as? String, let uidd = velt["uid"] as? String {
userNew.name = name
userNew.username = usernamerr
userNew.uid = uidd
if self.checklers.contains(uidd) {
print("already")
}
else {
if userNew.uid != uidi {
self.filteredUsers.append(userNew)
self.activityInd.stopAnimating()
self.checklers.append(uidd)
}
print("added a user")
}
}
}
}
self.tableViewSearchUser.reloadData()
}
}
})
ref.removeAllObservers()
}
// filteredUsers = users.filter( { ($0.username?.lowercased().contains(searchController.searchBar.text!.lowercased()))! })
}
tableViewSearchUser.reloadData()
}
Please add any advice, thanks.
Just for searching one or two users, each time a user would need to fetch all the records and putting them all in an array (all in memory). You want SQL-where query function, but Firebase is just different and doesn't have it.
Problem with storing fetching all data approach:
1) Storing just all the user's information in an array of user objects is NOT scalable on client's device.
2) When the number of users gets to ten of thousands, a day worth of search by a single user will eat up a sizable amount of real time database read quota.
3) Stale user data, an user has to re-download all the users just becauase on user changed his name to Doggie1 to doggieTwo.
Solutions:
1) If you haven't done so already, I suggest the options of doing some server-side filtering first by following the best practice here:
Firebase Retrieving Data - Filtering
Downloading a sub-set of user that fits some criteria and then do a bit of client-side filtering. Still is problematic when users get to tens of thousands.
Firebase has a client-size data persistence feature, but in your case if there filtering rule doesn't fit your need, you need do you own caching with some persistent storage solution. Instead of putting the fetched object in an Array[User], I would store each in a database SQLite on iOS and Android apps.
2) Implement a ElasticSearch with the FlashLight plugin, this involves some extra setup (I know, I've been through it, I learned quite a bit), but it is well worth it for autocomplete and search functions that Firebase currently doesn't support.
A pluggable integration with ElasticSearch to provide advanced content searches in Firebase.

A loop to continuously collect the Wifi strength of nearby access points

Assume I have an iPhone connected to a wifi network with 3+ access points.
I'd like to collect all possible fields around wifi access strength/signal/etc from EACH access point and use that to triangulate, even while in background.
while true {
...
for access_point in access_points {
...
signal_strength = ...
}
}
I've been reading previous SO answers and other posts, and seems like it wasn't allowed on iOS without a jailbreak for a while, but is now availiable again.
Anyone can show a code snippet of how I'd go about doing this? All new to iOS development..
It's been quite a while since I worked with this, so I did a quick check again and now I am fairly certain you misunderstood something you've read. As far as I can tell, Apple did not suddenly revert their previous decision to restrict the public frameworks to scan for access points, i.e. specific MAC addresses and their signal strength.
You can query the specific rssi (signal strength) for a network (i.e. for an ssid), but not for individual MAC addresses. Before iOS 5 you could do that using private APIs, then you could do it with private APIs on a jailbroken device and that's pretty much it.
I don't have the code of my own, old stuff at hand (I used to do this for indoor location tracking before we switched to use iBeacons), so I can't provide you with a sample snippet myself. My code is dated and no longer functioning anyways, but you might find something here.
I would be really interested in the sources you mention that claim iOS 10 now allows this again. Apple closed this for privacy considerations (officially at least, and although this might be true in part it also means developers dealing with location-tracking now need to rely fully on Apple's framework for that only), so I highly doubt they went back on it.
Also, note that this is for sure not something trivial, especially if you're new to iOS development. I haven't even tackled the background idea, you can safely forget about that, because no matter what you do, you will not have a scanner that runs continuously in the background. That's against a very core principle of iOS programming.
I've answered how to ping ALL wifi networks in this question;
func getInterfaces() -> Bool {
guard let unwrappedCFArrayInterfaces = CNCopySupportedInterfaces() else {
print("this must be a simulator, no interfaces found")
return false
}
guard let swiftInterfaces = (unwrappedCFArrayInterfaces as NSArray) as? [String] else {
print("System error: did not come back as array of Strings")
return false
}
for interface in swiftInterfaces {
print("Looking up SSID info for \(interface)") // en0
guard let unwrappedCFDictionaryForInterface = CNCopyCurrentNetworkInfo(interface) else {
print("System error: \(interface) has no information")
return false
}
guard let SSIDDict = (unwrappedCFDictionaryForInterface as NSDictionary) as? [String: AnyObject] else {
print("System error: interface information is not a string-keyed dictionary")
return false
}
for d in SSIDDict.keys {
print("\(d): \(SSIDDict[d]!)")
}
}
return true
}
You may have seen this feature in jailbroken apps as it is possible to do this using private libraries, which means that apps that are sold on the iOS store can't be sold if they utilise them.

Get contact image displayed in incoming phone calls on iOS

I am inserting a new contact with Apple's Contacts framework. The image is a .png from Asset catalog. After the successful insertion the new contact is visible with the correct image in the Contacts app. However, when there is an incoming call from the newly inserted contact the image is NOT displayed.
I couldn't find any reliable information about the exact cases when does the iOS display the contact image. Is it true that images will only appear if the user sets it manually? Did I miss something? Could you please point me to a good documentation or provide me an explanation? (The only relevant information is in this article: https://support.apple.com/en-us/HT202158 but I fulfill every requirement and it is probably not closely related.)
Code for the contact insertion:
let newContact = CNMutableContact()
...
if let image = UIImage(named: "ContactImage") {
newContact.imageData = UIImagePNGRepresentation(image)
}
...
let saveRequest = CNSaveRequest()
saveRequest.addContact(newContact, toContainerWithIdentifier: nil)
do {
try contactStore.executeSaveRequest(saveRequest)
log.debug("New contact successfully saved!")
} catch let error as NSError {
log.error(error.localizedDescription)
} catch {
log.error("Unknown error happened during contact saving.")
}
I've contacted Apple Developer Technical Support and their engineers determined that this would be best handled as a bug report. The submitted bug's ID is 26033574.
UPDATE
Apple asked me the following question.
Can you please share the vcard and image you’re using on the contact card?
I shared the vCard with them and unfortunately there was no image in it, although on iOS (and macOS) the image was clearly visible.
I found that saving the contact two times in a row solved the problem.
Save the contact
Add the image to the contact
Resave the contact

PFQueryTableView isn't up-to-date with Parse-data (Swift 2)

I'm new to this forum, and – more importantly – I'm also new to the Swift (2) language – and actually in coding at all.
So at the moment I'm trying to work with Parse in Xcode 7 (Swift 2). To be more specific: I'm working with a PFQueryTableView to display the data, I set up in the Parse class, in the app. But my problem is that when I update this data on the Parse website and I run the app in the simulator, the tableview with data isn't up-to-date with my new data from the Parse-website.
After going through other topic-related posts, this is the code I came up with:
let query = PFQuery(className: "myClass")
query.findObjectsInBackgroundWithBlock { (objects, error) -> Void in
if error == nil {
print("Successfully retrieved: \(objects)")
} else {
print("Error: \(error)")
}
}
Now, when I run the app I can see the right data in the Target Output, but in the simulator it's still the old data. So I guess there must be a line of code in the "if error == nil { }"-section. I already tried several lines of codes which I got from other threads, but they all didn't work. And like I said before: I'm still a beginner in coding, so I just can't figure out myself how to do this.
Hopefully one of you guys can help me out. And if I need to be more specific or something, just ask!
Thanks in advance!

Resources