I'm trying to set up a chat room in IOS with firebase. Things work fine when I test in the simulator of the firebase console but do not work in IOS app.
The structure I use is like this
root/members/room-id/auth.uid/userdata
root/messages/room_id/messages/message
I create a new room in IOS with
- (void)initRoom
{
NSMutableDictionary *mdata = [[NSMutableDictionary alloc] init];
FIRUser *user = [FIRAuth auth].currentUser;
mdata[#"uid"] = user.uid;
// get the key for the new room
roomKey = [[_rootRef child:#"messages"] childByAutoId].key;
if (roomKey != nil) {
// add auth.uid to member/roomkey
NSString *memberID = [[[_rootRef child:#"members"] child: roomKey ] child: user.uid ].key;
[[[[_rootRef child:#"members"] child: roomKey ] child: memberID ] setValue:mdata];
[self addMemberToRoom];
}
}
and add the other member for that room (using hard coded uid, for now):
-(void) addMemberToRoom{
NSString *memberID = [[[_rootRef child:#"members"] child: roomKey ] child: #"QLfRoGpoCjWpzira7fljBj8g3EJ3"].key;
NSMutableDictionary *mdata = [[NSMutableDictionary alloc] init];
mdata[#"uid"] = #"QLfRoGpoCjWpzira7fljBj8g3EJ3";
if (memberID !=nil) {
[[[[_rootRef child:#"members"] child: roomKey ] child: memberID ] setValue:mdata];
}
// start listener
[self observeMessages];
}
The console show this for members:
and this for messages:
and start the listener like this:
-(void)observeMessages
{
_msgHandle = [[[_rootRef child:#"messages"] child: roomKey] observeEventType:FIRDataEventTypeChildAdded withBlock:^(FIRDataSnapshot *snapshot) {
NSDictionary<NSString *, NSString *> *message = snapshot.value;
NSString *name = message[#"senderId"];
NSString *text = message[#"message"];
[self addMessagewithId:name andText:text];
// animates the receiving of a new message on the view
[self finishReceivingMessage];
}];
}
This is all working well to add a message to the database and see it in the app when I set rules like this:
{
"rules": {
"members": {
".read": "auth !== null",
".write": "auth !== null",
},
"messages": {
".write":"auth !== null",
".read": "auth !== null",
"$room_id": {
}
}
}
}
Now, since I don't want everybody being able to read the messages I set the rule to:
{
"rules": {
"members": {
".read": "auth !== null",
".write": "auth !== null",
},
"messages": {
".write": "auth !== null",
"$room_id": {
".read": "root.child('members/'+$room_id+'/'+auth.uid).exists()",
}
}
}
}
When I do this, the listener in the IOS app will not receive any call. Checking for the room_id and user created from the app with the simulator in the firebase console the read is flagged OK.
My assumption was, that the listener was initialized before the new members where created but even delaying the initializing did not help.
Could you help me by pointing me to the right direction? Thanks a lot!
OK, I found a solution that works for now. The observer for the chatroom was created before the chatroom is available in the members list, thus the .read rule returns false.
My workaround is setting an observer to the members list that starts the observer for messages when it fires.
This is my code:
-(void) getLastRoom // invoked when new room is added to members node
{
FIRUser *user = [FIRAuth auth].currentUser;
NSString *uid = user.uid;
_msgHandle = [[[[_rootRef child:#"members"] child: roomKey] queryEqualToValue: uid] observeEventType:FIRDataEventTypeValue withBlock:^(FIRDataSnapshot *snapshot) {
NSString *chatRoom = snapshot.key; //-> returns the roomkey of the chatroom
if ([chatRoom isEqualToString:roomKey]){
[self observeMessages];
}
}];
}
Hope it might help somebody.
Related
I am a beginner in firebase and in iOS. I am trying to change a project from parse to firebase.I successfully created and updated the firebase database. But while trying to retrieve data from firebase its just not working for me.
Here's the code I used.
self.ref = [[FIRDatabase database] reference];
NSString *userID = [FIRAuth auth].currentUser.uid;
[[[ref child:#"users"] child:userID] observeSingleEventOfType:FIRDataEventTypeValue withBlock:^(FIRDataSnapshot * _Nonnull snapshot) {
NSLog(#"%#",snapshot.value);
// Get user value
}withCancelBlock:^(NSError * _Nonnull error) {
NSLog(#"%#", error.localizedDescription);
}];
The control just skips the whole block. I can't figure out the problem.
The firebase guide is very hard to understand. Please tell me how to get values to a dictionary from a firebase child.
DatabaseReference database =
FirebaseDatabase.getInstance().getReference();
database.child("notes").addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
List notes = new ArrayList<>();
for (DataSnapshot noteDataSnapshot : dataSnapshot.getChildren()) {
Note note = noteDataSnapshot.getValue(Note.class);
notes.add(note);
}
adapter.updateList(notes);
}
...
});
I'm integrating multi-room chat in my app and I'm stuck with getting a list of all chat room a specific user is member of.
The structure looks like this:
The rooms and members are created with childByAutoId like this:
FIRUser *user = [FIRAuth auth].currentUser;
mdata[#"uid"] = user.uid;
roomKey = [[_rootRef child:#"messages"] childByAutoId].key;
NSString *memberID = [[[_rootRef child:#"members"] child: roomKey ] child: user.uid ].key;
// set Meta data for member to be able to recognize later
[[[[_rootRef child:#"members"] child: roomKey ] child: memberID ] setValue:mdata];
Now I'm trying the get the list of rooms for a (hard coded) user like that:
-(void) getRoomKeys {
[[[[_rootRef child: #"members"] queryOrderedByChild:#"uid" ] queryEqualToValue:#"QLfRoGpoCjWpzira7fljBj8g3EJ3"]
observeEventType:FIRDataEventTypeValue withBlock:^(FIRDataSnapshot *snapshot) {
NSDictionary<NSString *, NSString *> *message = snapshot.value;
}];
}
This return 0 key/value pairs.
When I take out the query I get all room keys. When I change the structure to this
I will get all rooms for that user but with this structure I can't add other members to that room. So I need to dig one level deeper.
So how to set the query for nodes that have been created by childByAutoId?
Thanks for your help!
Try considering this data structure.
{
"rooms": {
"-KQgDxLIt88yPt6nacDu": { ... }
},
"members": {
"QLfRoGpoCjWpzira7fljBj8g3EJ3": { ... }
},
"member-rooms": {
"QLfRoGpoCjWpzira7fljBj8g3EJ3": {
"-KQgDxLIt88yPt6nacDu": true
}
}
}
You can retrieve the keys of the rooms a member is part of by observing member-rooms/{uid}:
[[_rootRef child: #"member-rooms/QLfRoGpoCjWpzira7fljBj8g3EJ3"] observeEventType:FIRDataEventTypeValue withBlock:^(FIRDataSnapshot *snapshot) {
NSLog("%#", snapshot.value); // the keys of the rooms of the member
}];
How do I discover what social media the user has chosen, using Xamarin on iOS?
Look at my example below:
using (UIActivityViewController actController = new UIActivityViewController(activityTypes, null))
{
actController.ExcludedActivityTypes = new NSString[]
{
UIActivityType.AddToReadingList,
UIActivityType.AirDrop,
UIActivityType.AssignToContact,
UIActivityType.CopyToPasteboard,
UIActivityType.Print,
UIActivityType.SaveToCameraRoll
};
Version deviceVersion = new Version(UIDevice.CurrentDevice.SystemVersion);
if (deviceVersion >= iosVersion8) {
actController.PopoverPresentationController.SourceView = buttonView;
}
PresentViewController(actController, true, null);
}
Try setting the completion handler like so:
actController.CompletionHandler += (NSString arg1, bool arg2) => {
if (arg1.Equals(UIActivityType.PostToFacebook))
{
Console.Write ("YOU CHOOSE FACEBOOK!");
}
};
I want to check if my array is empty or null and not null or not empty. Below is some sample code I have written. Can you tell me if this is on the right track?
/// first time get data there
{
Bonds = Null;
User = {
DOB = "12/09/1988";
about = "test about";
city = CA;
};
success = True;
}
////////Second time get data there
{
Bonds = (
{
DOB = "12/09/1988";
about = "";
city = CA;
},
{
DOB = "12/09/1988";
about = "";
city = CA;
}
);
User = {
DOB = "12/09/1988";
about = about;
city = CA;
};
success = True;}
#try
{
if([Your_array objectAtIndex:int]== (id)[NSNull null] || [Your_array objectAtIndex:int]==0)
{
// if index get null
}
else
{
//your code if array index is not null
}
}
#catch (NSException * e)
{
NSLog(#"NSException");
}
If you are asking how to check for an empty array in Objective C (you mentioned iPhone SDK but not the language- Swift or Objective C) you can simply check the count.
if ([myArray count]==0) // the array is empty
{
...
}
try this
if(![Bonds isKindOfClass:[NSArray Class]]) // for non nil array and
if([Bounds firstObject]) //to check if array having at least one element
if array is not nil, and if not - check if it is not empty.
if (!array || !array.count){
......
}
try this
if(array && ![array isEqual:[NSNull null]] && [array count] > 0)
{
}
You can check like this
if ((NSNull*) Bonds !=[NSNull null] && Bonds!=nil && [array count] > 0)
{
}
if (!array || !array.count){
......
}
So in a block I am getting and parsing a JSON object that looks like this (any time you see "<...>" assume properly formed data)(also this is only one of the objects in question):
{
asset = {
<...>
};
<...>
sections = (
{
<...>
fields = (
);
items = (
);
},
{
<...>
fields = (
);
items = (
);
},
{
<...>
fields = (
);
items = (
{
<...>
properties = {
title = "We welcome guests...";
};
},
{
<...>
properties = {
title = "More text";
};
},
{
<...>
properties = {
title = "Opportunity Insert...";
};
}
);
},
{
<...>
fields = (
{
<...>
values = (
Private,
Public
);
},
{
<...>
values = (
);
},
{
<...>
values = (
);
}
);
items = (
);
},
{
<...>
fields = (
{
<...>
values = (
);
},
{
<...>
values = (
);
}
);
items = (
);
}
);
}
The code to get this(using AFNetworking):
NSMutableURLRequest* req = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:AppsURL([[NSUserDefaults standardUserDefaults] objectForKey:kAuthToken])]];
AFHTTPRequestOperation* op = [[AFHTTPRequestOperation alloc] initWithRequest:req];
[op setResponseSerializer:[[AFJSONResponseSerializer alloc] init]];
[op setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject) {
if (responseObject != nil&&[responseObject isKindOfClass:[NSDictionary class]]) {
NSDictionary* dict = (NSDictionary*)responseObject;
if (dict[#"apps"]&&[dict[#"apps"] isKindOfClass:[NSArray class]]) {
apps = dict[#"apps"];
dispatch_async(dispatch_get_main_queue(), ^{
[self.tableView reloadData];
});
return;
}
}
NSLog(#"Error Loading apps:%#",responseObject);
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
NSLog(#"Error:%#",error);
NSLog(#"Response:%#",operation.response.description);
}];
[op start];
At this point everything is loading into memory and working perfectly. I set this to a class-level NSArray and then use that NSArray to fill a table. The problem comes when I try to retrieve the data after the user picks one of the items from the table. I then use the index and pull that object from the NSArray to find that is looks like this(note the fact that all item and field arrays are now empty):
{
asset = {
<...>
};
<...>
sections = (
{
<...>
fields = (
);
items = (
);
},
{
<...>
fields = (
);
items = (
);
},
{
<...>
fields = (
);
items = (
);
},
{
<...>
fields = (
);
items = (
);
}
);
}
Code for select:
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{
if (indexPath.row < apps.count) {
//the output of this is what I copy and pasted
NSLog(#"app data to be cleaned up:%# \r app data sent:%#",apps[indexPath.row],((NSDictionary*)apps[indexPath.row]).mutableCopy);
//I originally thought the problem was here, but the output above proved me wrong
NSMutableDictionary *app = [Functions recurseDictionaryForNull:((NSDictionary*)apps[indexPath.row]).mutableCopy];
[[NSUserDefaults standardUserDefaults] setObject:app
forKey:#"app"];
MainMenuViewController* mainMenu = (MainMenuViewController*)[self.storyboard instantiateViewControllerWithIdentifier:#"mainMenu"];
[self.navigationController setViewControllers:#[mainMenu] animated:YES];// reset nav stack
}
}
I'm kinda at a lose... any ideas what could be doing this and how to fix it??
It was the data from the server. I was told 2 "apps" were the same except for one item and turns out they were missing all of the fields and items as well. Thanks Dima and Mike for taking the time anyways!