I want to get offline user (friend) status:
My code is working fine when user is online, so i am getting user status but when he goes offline user.primaryResource.presence.status gives nil value.
XMPPUserCoreDataStorageObject *user = [[self fetchedResultsController] objectAtIndexPath:indexPath];
NSLog(#"Status: %#",user.primaryResource.presence.status);
After user goes offline i check the XMPPResourceCoreDataStorageObject table for particular jidStr its give me zero objects means when user goes offline its remove the ResourcesObject of that user.
So, there is any possibility to get a status of that user.
You check the source code of XMPPUserCoreDataStorageObject
- (void)updateWithPresence:(XMPPPresence *)presence streamBareJidStr:(NSString *)streamBareJidStr
{
XMPPResourceCoreDataStorageObject *resource =
(XMPPResourceCoreDataStorageObject *)[self resourceForJID:[presence from]];
if ([[presence type] isEqualToString:#"unavailable"] || [presence isErrorPresence])
{
if (resource)
{
[self removeResourcesObject:resource];
[[self managedObjectContext] deleteObject:resource];
}
}
else
{
if (resource)
{
[resource updateWithPresence:presence];
}
else
{
XMPPResourceCoreDataStorageObject *newResource;
newResource = [XMPPResourceCoreDataStorageObject insertInManagedObjectContext:[self managedObjectContext]
withPresence:presence
streamBareJidStr:streamBareJidStr];
[self addResourcesObject:newResource];
}
}
[self recalculatePrimaryResource];
}
You can see the resource will be removed if offline.
For myself, I check user.primaryResource?.presence?.type() == "available" as online, other cases as offline. (Assume user is the XMPPUserCoreDataStorageObject you got from db)
Related
I need to display entire friend list's avatar images inside UITableView.
I could as well ask this into Quickblox forums but seems like their support is less responsive there.
I have read Quickblox documentation but can't find an efficient way of getting user's avatar images. All I see is [QBContent TDownloadFileWithBlobID], but I do not know how to use it.
I am fetching contacts using chatContactListDidChange delegate call like below. Now how can I also get all these users' avatar images also?
Note that friendsArray is my data source for the table view, so ideally I would want to store the avatar images as part of the same array.
- (void)chatContactListDidChange:(QBContactList *)contactList
{
NSLog(#"contact list changed");
NSLog(#"current contact list %#", [QBChat instance].contactList);
[self fetchContacts:[QBChat instance].contactList.contacts];
}
- (void) fetchContacts : (NSArray *) contactArray
{
NSMutableArray * userIDArray = [[NSMutableArray alloc] init];
for (QBContactListItem * contact in contactArray)
{
NSString * userIDString = [NSString stringWithFormat:#"%ld", (unsigned long)contact.userID];
[userIDArray addObject:userIDString];
}
if (!userIDArray.count)
{
return;
}
NSString * requestString = [userIDArray componentsJoinedByString:#","];
[QBUsers usersWithIDs:requestString delegate:self context:#"FetchFriends"];
}
- (void)completedWithResult:(Result *)result context:(void *)contextInfo
{
if([result isKindOfClass:[QBUUserPagedResult class]])
{
NSString * context = (__bridge NSString *)contextInfo;
// Success result
if(result.success)
{
QBUUserPagedResult * pagedResult = (QBUUserPagedResult *)result;
if ([context isEqualToString:#"FetchFriends"])
{
if (friendsArray)
{
[friendsArray removeAllObjects];
}
else
{
friendsArray = [[NSMutableArray alloc] init];
}
QBUUser * user = [pagedResult.users objectAtIndex:0];
//user.blobID
friendsArray addObjectsFromArray:pagedResult.users];
}
}
else
{
NSLog(#"Error getting users: %#", context);
}
}
}
Use QBUUser's fields - customData for public url of user's image and blobID for uploaded blob.
Image --> [QBContent TUploadFile...] --> Getting callback with result (QBCFileUploadTaskResult) --> getting blob (QBCBlob) --> save blob id to user.blobID --> get public url of your image: [currentBlob publicURL] --> save to user.customData --> update user: [QBUsers updateUser...]
Hope it helps you.
I'm developing an iOS application with Simple Notification Service (SNS) from Amazon Web Services. At this point the app registers the device to a Topic and can receive push notifications, which are published to the Topic. It is possible to subscribe a device to many Topics.
Now I'm trying to unsubscribe a device from a specific Topic, but the SNSUnsubscribeRequest needs a SubscriptionARN. I've tried to use the EndpointARN from the device, but it seems I've to use an extra SubscriptionARN for the combination of EndpointARN and TopicARN. How do I get this ARN?
In this post: How do you get the arn of a subscription? they ask for the whole list of subscribers and compare each EndpointARN with the EndpointARN of the device. This cant be the right way i think.
Subscribe to Topic
// Check if endpoint exist
if (endpointARN == nil) {
dispatch_async(dispatch_get_main_queue(), ^{
[[self universalAlertsWithTitle:#"endpointARN not found!" andMessage:#"Please create an endpoint for this device before subscribe to topic"] show];
});
return NO;
}
// Create topic if not exist
NSString *topicARN = [self findTopicARNFor:topic];
if (!topicARN) {
[self createTopic:topic];
topicARN = [self findTopicARNFor:topic];
}
// Subscribe to topic if exist
if (topicARN) {
SNSSubscribeRequest *subscribeRequest = [[SNSSubscribeRequest alloc] initWithTopicArn:topicARN andProtocol:#"application" andEndpoint:endpointARN];
SNSSubscribeResponse *subscribeResponse = [snsClient subscribe:subscribeRequest];
if (subscribeResponse.error != nil) {
NSLog(#"Error: %#", subscribeResponse.error);
dispatch_async(dispatch_get_main_queue(), ^{
[[self universalAlertsWithTitle:#"Subscription Error" andMessage:subscribeResponse.error.userInfo.description] show];
});
return NO;
}
}
return YES;
The method findTopicARNForTopic already iterates over the list of Topics and compare the suffix with the topic name. I really don't know if this is the best practice.
Unsubscribe from Topic
NSString *topicARN = [self findTopicARNFor:topic];
if (topicARN) {
SNSUnsubscribeRequest *unsubscribeRequest = [[SNSUnsubscribeRequest alloc] initWithSubscriptionArn:topicARN];
SNSUnsubscribeResponse *unsubscribeResponse = [snsClient unsubscribe:unsubscribeRequest];
if (unsubscribeResponse.error) {
NSLog(#"Error: %#", unsubscribeResponse.error);
}
}
For now I ask for the whole subscriber list and compare the EndpointARN with the EndpointARN of the Device. With the following method i get the subscription arn:
- (NSString *)findSubscriptionARNForTopicARN:(NSString *)topicARN
{
// Iterate over each subscription arn list for a topic arn
NSString *nextToken = nil;
do {
SNSListSubscriptionsByTopicRequest *listSubscriptionRequest = [[SNSListSubscriptionsByTopicRequest alloc] initWithTopicArn:topicARN];
SNSListSubscriptionsByTopicResponse *response = [snsClient listSubscriptionsByTopic:listSubscriptionRequest];
if (response.error) {
NSLog(#"Error: %#", response.error);
return nil;
}
// Compare endpoint arn of subscription arn with endpoint arn of this device
for (SNSSubscription *subscription in response.subscriptions) {
if ([subscription.endpoint isEqualToString:endpointARN]) {
return subscription.subscriptionArn;
}
}
nextToken = response.nextToken;
} while (nextToken != nil);
return nil;
}
and with this method i remove the device from a topic:
- (void)unsubscribeDeviceFromTopic:(NSString *)topic
{
NSString *subscriptionARN = [self findSubscriptionARNForTopic:topic];
if (subscriptionARN) {
SNSUnsubscribeRequest *unsubscribeRequest = [[SNSUnsubscribeRequest alloc] initWithSubscriptionArn:subscriptionARN];
SNSUnsubscribeResponse *unsubscribeResponse = [snsClient unsubscribe:unsubscribeRequest];
if (unsubscribeResponse.error) {
NSLog(#"Error: %#", unsubscribeResponse.error);
}
}
}
You could also store the SubscriptionArn in the SubscribeResponse and use this value in the UnSubscribeRequest.
I am trying to print out all of my phone's contacts to the console, using NSLog(). Currently this code is just printing (null).
.h
#property (nonatomic, strong) NSMutableArray *contactsObjects;
.m
#synthesize contactsObjects;
//lazy instantiation.
- (NSMutableArray *)contactsObjects
{
if(!contactsObjects)
{
contactsObjects = [[NSMutableArray alloc]init];
}
return contactsObjects;
}
- (void)viewWillAppear:(BOOL)animated
{
CFErrorRef error = nil;
// Request authorization to Address Book
ABAddressBookRef addressBookRef = ABAddressBookCreateWithOptions(NULL, &error);
if (ABAddressBookGetAuthorizationStatus() == kABAuthorizationStatusNotDetermined) {
ABAddressBookRequestAccessWithCompletion(addressBookRef, ^(bool granted, CFErrorRef error) {
if (granted) {
// First time access has been granted, add all the user's contacts to array.
CFMutableArrayRef contactsObjects = ABAddressBookCopyArrayOfAllPeople(addressBookRef);
} else {
// User denied access.
// Display an alert telling user that they must allow access to proceed to the "invites" page.
}
});
}
else if (ABAddressBookGetAuthorizationStatus() == kABAuthorizationStatusAuthorized) {
// The user has previously given access, add all the user's contacts to array.
CFMutableArrayRef contactsObjects = ABAddressBookCopyArrayOfAllPeople(addressBookRef);
}
else {
// The user has previously denied access
// Send an alert telling user that they must allow access to proceed to the "invites" page.
}
NSLog(#"%#", contactsObjects);
}
I get two warnings here:
I have no idea what I am supposed to do in order to properly print the names and numbers of my contacts to the console.
How do I print my contacts names and numbers?
You have a scope problem with your code. The contactsObjects variables in viewWillAppear: are not related to the ivar you have called contactsObjects. You're declaring new variables that are using the same name. The NSLog() at the end, on the other hand, is the ivar. But setting those other variables didn't put anything into the ivar, so you see (null), which is how NSLog() represents "no object".
Fix this by not making new variable declarations, but using the ivar.
if (granted) {
contactsObjects = ABAddressBookCopyArrayOfAllPeople(addressBookRef);
else if (ABAddressBookGetAuthorizationStatus() == kABAuthorizationStatusAuthorized) {
contactsObjects = ABAddressBookCopyArrayOfAllPeople(addressBookRef);
You will also need to cast these:
contactsObjects = (__bridge_transfer NSArray *)ABAddressBookCopyArrayOfAllPeople(addressBookRef);
(Also, the function doesn't return a mutable array, so you may have trouble down the road with that.)
The second problem is that ABAddressBookRequestAccessWithCompletion() doesn't stop and wait for its completion Block to run. While access is being requested, the rest of your method carries on, so you reach the NSLog() before contactsObjects is actually set in that case.
You say it prints out null and that you get an error. But this would explain your error.
contactObjects is defined within the if block and the else if block. So by the time you are outside of your conditional it's no longer defined.
Try this
- (void)viewWillAppear:(BOOL)animated
{
CFErrorRef error = nil;
// Request authorization to Address Book
ABAddressBookRef addressBookRef = ABAddressBookCreateWithOptions(NULL, &error);
if (ABAddressBookGetAuthorizationStatus() == kABAuthorizationStatusNotDetermined) {
ABAddressBookRequestAccessWithCompletion(addressBookRef, ^(bool granted, CFErrorRef error) {
if (granted) {
// First time access has been granted, add all the user's contacts to array.
contactsObjects = ABAddressBookCopyArrayOfAllPeople(addressBookRef);
} else {
// User denied access.
// Display an alert telling user that they must allow access to proceed to the "invites" page.
}
});
}
else if (ABAddressBookGetAuthorizationStatus() == kABAuthorizationStatusAuthorized) {
// The user has previously given access, add all the user's contacts to array.
contactsObjects = ABAddressBookCopyArrayOfAllPeople(addressBookRef);
}
else {
// The user has previously denied access
// Send an alert telling user that they must allow access to proceed to the "invites" page.
}
NSLog(#"%#", contactsObjects);
}
Hitting a very strange issue here, which seems to me to be an issue with the EventKit API and I just want to check it's nothing I'm doing.
Test case 1:
Reminders are enabled in Privacy for the app
The device has an iCloud account, but it's set to not sync reminders
I can create a local reminders list in the 'Reminders' app from Apple
ISSUE - Trying to create a new calendar of entity type EKEntityTypeReminder with a source of type EKSourceTypeLocal fails
Test case 2:
Reminders are enabled in Privacy for the app
The device has no iCloud account
I can create a local reminders list in the 'Reminders' app from Apple
I can create a local reminders list via the EK API
Test case 3:
Reminders are enabled in Privacy for the app
The device has an iCloud account and is set to sync reminders
I can create an iCloud reminders list in the 'Reminders' app from Apple
I can create an iCloud reminders list via the EK API
Am I going crazy or is this a bug with the API?
Cheers!
Here's the code:
EKCalendar *remindersList = nil;
NSString *remindersListIdent = [[NSUserDefaults standardUserDefaults] objectForKey:kReminderListIdentDefaultsKey];
if(remindersListIdent) {
remindersList = [store calendarWithIdentifier:remindersListIdent];
if(remindersList) {
// has valid reminders list so save reminder and return (don't run rest of function)
[self saveReminder:reminder toCalendar:remindersList withTypeLabel:reminderTypeLabel];
return;
}
}
NSArray *currentCalendars = [store calendarsForEntityType:EKEntityTypeReminder];
for(EKCalendar *cal in currentCalendars) {
if([[cal title] isEqualToString:#"My App Name"]) {
remindersList = cal;
[[NSUserDefaults standardUserDefaults] setObject:[remindersList calendarIdentifier] forKey:kReminderListIdentDefaultsKey];
[[NSUserDefaults standardUserDefaults] synchronize];
[self saveReminder:reminder toCalendar:remindersList withTypeLabel:reminderTypeLabel];
return;
}
}
EKSource *localSource = nil;
for (EKSource *source in store.sources) {
if (source.sourceType == EKSourceTypeCalDAV && [source.title isEqualToString:#"iCloud"]) {
localSource = source;
break;
}
}
if(localSource) {
remindersList = [self newCalendarListInSource:localSource];
}
if(!remindersList) {
for (EKSource *source in store.sources) {
if (source.sourceType == EKSourceTypeLocal) {
localSource = source;
remindersList = [self newCalendarListInSource:localSource];
if(remindersList) {
break;
}
}
}
}
if(!remindersList) {
dispatch_async(dispatch_get_main_queue(), ^{
// show error message
});
}
else {
[[NSUserDefaults standardUserDefaults] setObject:[remindersList calendarIdentifier] forKey:kReminderListIdentDefaultsKey];
[[NSUserDefaults standardUserDefaults] synchronize];
[self saveReminder:reminder toCalendar:remindersList withTypeLabel:reminderTypeLabel];
}
And this is the contents of newCalendarListInSource:
EKCalendar *remindersList;
remindersList = [EKCalendar calendarForEntityType:EKEntityTypeReminder eventStore:store];
remindersList.source = localSource;
[remindersList setTitle:#"My App Name"];
NSError *listCreateError = nil;
[store saveCalendar:remindersList commit:YES error:&listCreateError];
if(!listCreateError) {
return remindersList;
}
else {
NSLog(#"Failed to create reminders list with error: %#", [listCreateError localizedDescription]);
For all still having a problem with this, check your EKSourceType that you use if it exists in your phone. For Swift, try using the EKSourceType.Exchange. Note that I have an Outlook/Exchange account synced to my phone.
I know that this is very vague, but when I used EKSourceType.Exchange, it worked for me. (Play with it)
Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 9 years ago.
Improve this question
i've been reading few posts about saving with core data. I noticed that most of the time everyone forgot to consider that the hardest part is the edit of objects rather than the creation.
I read 3 different books about core data, i will share with you all the methods those books use. and i would be curious to know which approach you would apply for your own application.
Core Data iOS Essentials - Packt Publishing
theres a RootVC, an AddCustomerVC and a EditCustomerVC. we want to create or edit a Customer
1) the user click the ADD button in the RootVC
2) the add button method create an object and sets it as the Object *myobject variable of the DetailVC
-(IBAction) addCustomer {
AddCustomerVC *addVC = [AddCustomerVC alloc]init];
addVC.customer = (Customer *) [NSEntityDescription insertNewObjectForEntityForName:#"Customer" inManagedObjectContext:self.managedObjectContext];
addVC.delegate = self;
[self.navigationController presentModalViewController:addVC animated:YES];
}
3) the detailVC sets the Customer instance attributes and calls the delegate method
-(IBAction) save {
customer.name = newName.text;
customer.surname = newSurname.text;
[delegate addVC:self selectedSave:YES];
}
4) if the user press Cancel in the addVC the actions calls the delegate method
-(IBAction) cancel {
[delegate addVC:self selectedSave:NO];
}
5) the RootVC delegate implementation check if the user saved and save the context
-(void) addVC:(UIViewController *)controller selectedSave:(BOOL)save {
if(!save) {
[self.managedObjectContext deleteObject:controller.customer];
}
NSError *error = nil;
if( ! [self.managedObjectContext save:&error] ) {
NSLog(#"Unresolved error %#, %#", error, [error userInfo]);
}
[self dismissModalViewControllerAnimated:YES];
}
1 edit) the user click on the cell and it calls the method for the cell selection where it create a Customer with the selected value and open the EditVC
-(void)tablewView:(UITableView *)tableview didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
EditCustomerVC editVC = [[EditCustomerVC alloc]init];
Customer *selectedCustomer = (Customer *) [self.fetchedResultsController objectAtIndexPath:indexPath];
editVC.customer = selectedCustomer;
[self.navigationController pushViewController:editVC animated:YES];
}
2 edit) the user press the save button, sets the values of the customer and it calls the delegate
-(IBAction) save {
customer.name = name.text;
customer.surname = surname.text;
[delegate editVC:self selectedSave:YES];
}
3b)if the user press cancel it calls the delegate
-(IBAction) cancel {
[delegate editVC:self selectedSave:NO];
}
4b) the delegate save the edited object
.(void)editVC:(UIViewController *)controller selectedSave:(BOOL)save {
if(save) {
NSError *error = nil;
if( ! [self.managedObjectContext save:&error] ) {
NSLog(#"Unresolved error %#, %#", error, [error userInfo]);
}
[self dismissModalViewControllerAnimated:YES];
}
Pro Core Data for iOS - Apress
We have a MasterVC and a TeamVC where we can create and edit a Team
1) when the user click the ADD button it calls the showTeamVC passing it the MasterVC and a team
-(void)showTeamVC {
TeamVC *teamVC = [[TeamVC alloc]initWithController:self andTeam:nil];
[self presentModalViewController:teamVC animated:YES];
}
2) the init of the TeamVC sets the passed value as its iVar
-(id)initWithController:(UIViewController *)controller andTeam:(Team *)team {
self.controller = controller;
self.team = team;
}
3) the viewDidLoad sets the fields of the view with the value that he got from the object
4) when the user press cancel the controller just gets dismissed
5) when the user click save it calls the save action that check if team is nil ( to see if you passed a team or not, so if you are adding or editing ) and calls the save or insert method of the master controller
-(IBAction)save {
if ( team != nil ){
team.name = nameTextField.text;
team.colors = colorsTextField.text;
[controller saveContext];
} else {
[controller insertTeamWithName: nameTextField.text andColors:colorsTextField.text];
}
[self dismissModalViewControllerAnimated:YES];
}
6) if you saved a new team it will be called the insertTeamWithName:andColors method in the MasterVC
-(void)insertTeamWithName:(NSString *)name andColors:(NSString *)colors {
NSManagedObjectContext *contextx = [self.fetchedResultsController managedObjectContext];
Team *newTeam = [NSEntityDescription insertNewObjectForEntityForName:#"Team" inManagedObjectContext:context];
[self saveContext];
}
7) if you edited a team it will be called the saveContext method in the MasterVC
-(void)saveContext {
NSManagedObjectContext *context = [self.fetchedResultsController managedObjectcontext];
NSError *error = nil;
if ( ! [context save:&error] ) {
NSLog(#"Error");
}
}
Core Data for iOS - core framework series
this is considered one of the best book for core data, even if is quite outdated
this has a total different approach
we have a RootVC and a PersonEditorVC we can add and edit Person
1) when the rootVC button add is pressed it calls the setCurrentPerson:nil method on the PersonEditorVC and open that view
- (void)addNewPerson {
[self.personEditorViewController setCurrentPerson:nil];
[self.navigationController pushViewController:self.personEditorViewController animated:YES];
}
2) the PersonEditorVC method setCurrentPerson gets called by the previous method. if person is nil it calls the Person initializer, if person is not nil it gets its objectID
- (void)setCurrentPerson:(AWPerson *)aPerson {
if( !aPerson )
{
self.title = #"Add person";
aPerson = [AWPerson
personInManagedObjectContext:self.editingContext];
}
else if( [aPerson managedObjectContext] != self.editingContext ) {
self.title = #"Edit person";
aPerson = (id)[self.editingContext
objectWithID:[aPerson objectID]];
}
if( currentPerson != aPerson ) {
[currentPerson release];
currentPerson = [aPerson retain];
}
}
3) the PersonEditorVC opens n set its textfield if the person is not nil, then gets the edited value from the textfield at each textFieldShouldReturn
- (void)textFieldDidEndEditing:(UITextField *)textField {
if( textField == self.firstNameTextField )
[self.currentPerson setFirstName:textField.text];
else if( textField == self.lastNameTextField )
[self.currentPerson setLastName:textField.text];
[self becomeFirstResponder];
}
4) when the user press cancel, it just goes back to the old controller, if he press save, it just save the context
- (IBAction)savePerson:(id)sender {
NSError *anyError = nil;
BOOL success = [[currentPerson managedObjectContext]
save:&anyError];
if( !success ) {
UIAlertView *errorAlert = [[UIAlertView alloc]
initWithTitle:#"Couldn't save this person"
message:[anyError localizedDescription]
delegate:self cancelButtonTitle:#"OK"
otherButtonTitles:nil];
[errorAlert show];
}
else {
[self.navigationController popViewControllerAnimated:YES];
}
}
5) it's important to note the initializer that its written in the auto generated model class
+ (id)personInManagedObjectContext:(NSManagedObjectContext *)moc {
return [NSEntityDescription
insertNewObjectForEntityForName:#"Person"
inManagedObjectContext:moc];
}
1 edit) if the user wants to edit a person and click on the person row in the table it gets called the tableview method where it just calls the setCurrentPerson, with a person
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
AWPerson *selectedPerson = [self.fetchedResultsController objectAtIndexPath:indexPath];
[self.personEditorViewController setCurrentPerson:selectedPerson];
[self.navigationController pushViewController:self.personEditorViewController animated:YES];
}
conclusions
here we have 3 totally different approach, from 3 of best books on Core Data.
Which is your fav approach? do you use a different one? why do you like one more than the other?
personally i find the last one to be the best, even if it can be less easier to code, it's surely the best syntax, more reusable and so on.
but for a small app i would probably use the first one.