So I have been trying to figure this out and the documentation just isn't clear enough.
I am trying to use AWS cognito user pools and federated identity pools.
Online they say you can connect the two then authenticate users via your user pools to gain credentials from your identity pool. Right now I have them connected and it's showing up as an authorization method but I am unable to figure out what to do in objective-c to get it to work. I can only get unauthorized users into my Federated identity pool not authorized users.
I also have everything working on the user pools (creating and authenticating users) So it's just getting them into the Federated identity pool for permissions.
Could someone post a code example in objective-c on how to do it? Or walk me through the logical steps on how to do it?
I've been looking at these links:
http://mobile.awsblog.com/post/TxGNH1AUKDRZDH/Announcing-Your-User-Pools-in-Amazon-Cognito
How to combine Cognito User Pools with external providers like Facebook?
and just about every other aws link
An Update to the question here is some code:
I am able to sign up and verify a user however it does not register on the console in the user federated identity pool only unauthenticated. Is it a problem with my AWSServiceConfiguration? (Etc)
This is the sign up method we use to create a user
RCT_EXPORT_METHOD(submitUser: (NSString*) email and:
(NSString*) gender and:
(NSString*) name and:
(NSString*) nickname and:
(NSString*) picture and:
(NSString*) phone_number and:
(NSString*) preferred_username and:
(NSString*) hashedPass and:
(RCTResponseSenderBlock)callback){
AWSCognitoIdentityUserPool *pool = [AWSCognitoIdentityUserPool CognitoIdentityUserPoolForKey:#"UserPool"];
NSMutableArray * attributes = [NSMutableArray new];
AWSCognitoIdentityUserAttributeType * userEmail = [AWSCognitoIdentityUserAttributeType new];
userEmail.name = #"email";
userEmail.value = email;
AWSCognitoIdentityUserAttributeType * userGender = [AWSCognitoIdentityUserAttributeType new];
userGender.name = #"gender";
userGender.value = gender;
AWSCognitoIdentityUserAttributeType * userName = [AWSCognitoIdentityUserAttributeType new];
userName.name = #"name";
userName.value = name;
AWSCognitoIdentityUserAttributeType * userNickname = [AWSCognitoIdentityUserAttributeType new];
userNickname.name = #"nickname";
userNickname.value = nickname;
AWSCognitoIdentityUserAttributeType * userPicture = [AWSCognitoIdentityUserAttributeType new];
userPicture.name = #"picture";
userPicture.value = picture;
AWSCognitoIdentityUserAttributeType * userPhone = [AWSCognitoIdentityUserAttributeType new];
userPhone.name = #"phone_number";
userPhone.value = phone_number;
AWSCognitoIdentityUserAttributeType * userPreferredUsername = [AWSCognitoIdentityUserAttributeType new];
userPreferredUsername.name = #"preferred_username";
userPreferredUsername.value = preferred_username;
[attributes addObject:userEmail];
[attributes addObject:userGender];
[attributes addObject:userName];
[attributes addObject:userNickname];
[attributes addObject:userPicture];
[attributes addObject:userPhone];
[attributes addObject:userPreferredUsername];
NSMutableString *str = [NSMutableString string];
[str appendString:name];
[str appendString:name];
NSString *immutableString = str; // Change later to unique identifier
[[pool signUp:immutableString password:hashedPass userAttributes:attributes validationData:nil]
continueWithBlock:^id(AWSTask<AWSCognitoIdentityUser*> *task) {
if (task.error) {
RCTLog(#"Error: %#", task.error);
}
if (task.exception) {
RCTLog(#"Exception: %#", task.exception);
}
if (task.result) {
RCTLog(#"Successfully registered user: %#",task.result);
}
callback(#[[NSNull null],#NO]);
return nil;
}];
}
Verify User with emailed code method
RCT_EXPORT_METHOD(verifyUser:(nonnull NSString *)userName and:
(nonnull NSString *)code and:
(RCTResponseSenderBlock)callback) {
AWSCognitoIdentityUserPool *pool = [AWSCognitoIdentityUserPool CognitoIdentityUserPoolForKey:#"UserPool"];
AWSCognitoIdentityUser * user = [pool getUser:userName];
[[user confirmSignUp:code] continueWithBlock:^id(AWSTask<AWSCognitoIdentityProviderConfirmSignUpResponse*> *task) {
bool pass = NO;
if(task.error){
RCTLog(#"Error: %#", task.error);
}
else if(task.exception){
RCTLog(#"Exception: %#", task.exception);
}
else{
RCTLog(#"Successfully confirmed user: %#",user.username); pass = YES;
}
// Return TRUE If Succead
if(pass){
callback(#[[NSNull null],#YES]);
}
else{
callback(#[[NSNull null],#NO]);
}
return nil;
}];
}
In Appdelegate.m
AWSServiceConfiguration *serviceConfiguration = [[AWSServiceConfiguration alloc] initWithRegion:AWSRegionUSEast1 credentialsProvider:nil];
AWSCognitoIdentityUserPoolConfiguration *configuration = [[AWSCognitoIdentityUserPoolConfiguration alloc]
initWithClientId:#"clientidhere"
clientSecret:#"clientsecrethere"
poolId:#"poolidhere"];
[AWSCognitoIdentityUserPool registerCognitoIdentityUserPoolWithConfiguration:serviceConfiguration userPoolConfiguration:configuration forKey:#"UserPool"];
AWSCognitoCredentialsProvider *credentialsProvider = [[AWSCognitoCredentialsProvider alloc]
initWithRegionType:AWSRegionUSEast1
identityPoolId:#"identitypoolIDhere"];
AWSServiceConfiguration *config = [[AWSServiceConfiguration alloc] initWithRegion:AWSRegionUSEast1 credentialsProvider:credentialsProvider];
[AWSServiceManager defaultServiceManager].defaultServiceConfiguration = config;
[AWSSQS registerSQSWithConfiguration:config forKey:#"USWest2SQS"]; // Needed for sqs work throughout the app
I solved this issue by providing a CustomIdentityProvider
#interface CustomIdentityProvider : NSObject <AWSIdentityProviderManager>
#property (nonatomic, retain) NSDictionary *tokens;
- (AWSTask *) logins;
#end
#implementation CustomIdentityProvider
- (AWSTask *) logins {
AWSTask *task = nil;
if (nil != self.tokens) {
return [AWSTask taskWithResult:self.tokens];
}
return task;
}
#end
When you create your AWSCognitoCredentialsProvider you need to assign the identityProviderManager
self.identityProviderManager = [[CustomIdentityProvider alloc] init];
self.credentialsProvider = [[AWSCognitoCredentialsProvider alloc]
initWithRegionType:AWSRegionUSEast1
identityPoolId:self.identityPoolId
identityProviderManager:self.identityProviderManager];
Once you have this set up, you need to populate the tokens NSDictionary. This is done after calling getSession and obtaining your AWSCognitoIdentityUserSession.
AWSCognitoIdentityUserSession *session; // Obtained from getSession
NSString *userPoolName = [NSString stringWithFormat:#"cognito-idp.us-east-1.amazonaws.com/%#", self.poolId];
NSDictionary *dict = #{userPoolName : session.idToken.tokenString};
self.customIdentityProvider.tokens = dict;
Assuming that you are generating your AWSAPIGatewayClient code via the SDKGeneration feature within API Gateway, you should be all set up for making your API Gateway calls as an authenticated user.
(PS. Don't forget to configure your Federated Identity to set your IAMS role for your Authenticated users to allow execute-api:Invoke.)
Related
Thankyou for reading,
PS: I am a beginner so I am not too good at this unfortunetaly, but any help would be very appreciated
So basically I want to archive a big array which contains Account objects, which they themselves contain:
1.a username in form of a NSString,
2.an encrypted password array filled with NSNumbers, and
3.a data array filled with service data objects.
The service data objects have the following:
encrypted serviceType (NSArray filled with NSNumbers) (whatever service the username and password is for)
encrypted username (NSArray filled with NSNumbers)
encrypted password (NSArray filled with NSNumbers)
Now weirdly when trying to archive and save this, I get two errors. One time it won't let me add service data objects to the data array in the Account class anymore, with the following error message (or at least they dont show up in the NSTableView I have, however it does say they exsist):
[<ServiceData 0x60000023bfa0> valueForUndefinedKey:]: this class is not key value
coding-compliant for the key service.
and two, when I try to login in the the username and password from the Account class, it retrieves the username and the first couple and last couple NSNumbers of my password correctly, but the rest of the NSNumbers for the password are in the trillions or something, so I'm wondering what is going wrong, any help would be greatly appreciated.
Here is the code for my instance variables, how I used the NSKeyedArchiver and unarchiver, and how I went about saving and loading the files. Again, please help me, I have been stuck on this for a while and this is kind-of my last resort. I have no idea what is happening!
ACCOUNT CLASS:
H file:
#interface Account : NSObject <NSCoding>
{
#private
NSString *username;
NSMutableArray *password;
NSMutableArray *accData;
}
#property NSString *username;
#property NSArray *password;
FULL M file:
-(id)initWithCoder:(NSCoder *)aDecoder
{
self = [super init];
if(self)
{
username = [aDecoder decodeObjectForKey:#"username"];
password = [aDecoder decodeObjectForKey:#"password"];
accData = [aDecoder decodeObjectForKey:#"data"];
}
return self;
}
-(void)encodeWithCoder:(NSCoder *)aCoder
{
[aCoder encodeObject:username forKey:#"username"];
[aCoder encodeObject:password forKey:#"password"];
[aCoder encodeObject:accData forKey:#"data"];
}
SERVICEDATA CLASS:
H file:
#interface ServiceData : NSObject <NSCoding>
{
#private
NSArray* serviceData;
NSArray* usernameData;
NSArray* passwordData;
}
#property NSArray* serviceData;
#property NSArray* usernameData;
#property NSArray* passwordData;
M file:
#import "Account.h"
#import "Crypt.h"
NSMutableArray *accounts;
NSInteger accountNumber = -1;
#implementation Account
#synthesize username;
#synthesize password;
- (id)initWithUsername:(NSString *)name withPassword:(NSMutableArray *)key
{
self = [super init];
if (self)
{
username = name;
password = key;
accData = [[NSMutableArray alloc]init];
}
return self;
}
/*
setters and getters
*/
-(NSString*)getUsername;
{
return username;
}
-(NSArray*)getPassword;
{
return password;
}
-(void)changePassword:(NSMutableArray*)newPassword;
{
NSInteger sizeOldPass = [password count];
NSInteger sizeNewPass = [newPassword count];
int changeXObjects = (int)(sizeNewPass - sizeOldPass);
int changeSize = abs(changeXObjects);
//adjusts size differences
if (changeXObjects < 0)
{
for(int i = 0; i < changeSize; i++)
{
[password removeLastObject];
}
}
else if (changeXObjects > 0)
{
for(int i = 0; i < changeSize; i++)
{
NSNumber *value = [NSNumber numberWithInt:0];
[password addObject:value];
}
}
//change password
NSInteger sizePass = [password count];
for (int k = 0; k < sizePass; k++)
{
[password replaceObjectAtIndex:k withObject:newPassword[k]];
}
}
-(NSMutableArray*)getAccData;
{
return accData;
}
-(void)setAccData:(NSMutableArray*)input
{
[input setArray: accData];
}
+(NSMutableArray*)getAccounts
{
return accounts;
}
+(NSInteger)getAccountNumber
{
return accountNumber;
}
+(void)setAccounts:(id)accs
{
accounts = accs;
}
+(void)setAccountNumber:(NSInteger)number
{
accountNumber = number;
}
/*
other methods
*/
+(void)addAccount:(id)acc
{
[accounts addObject:acc];
}
+(void)deleteAccount:(NSInteger)index
{
[accounts removeObjectAtIndex:index];
}
-(void)addAccData:(id)input
{
[accData addObject:input];
}
-(void)deleteAccDataAt:(NSInteger)index
{
[accData removeObjectAtIndex:index];
}
+(bool)checkPassword:(NSString*)passwordIn accountNumber:(NSInteger)index
{
NSMutableArray *passwordInputCrypt = [Crypt encrypt:passwordIn];
NSMutableArray *passwordCrypt = [accounts[index] getPassword];
NSInteger lengthPassword = [passwordInputCrypt count];
bool correctPassword = true;
if([passwordCrypt count] == [passwordInputCrypt count])
{
for(int i = 0; i < lengthPassword; i++)
{
if(passwordCrypt[i]!=passwordInputCrypt[i])
correctPassword = false;
}
}
else
{
correctPassword = false;
}
if(correctPassword == true)
{
return true;
}
return false;
}
-(id)initWithCoder:(NSCoder *)aDecoder
{
self = [super init];
if(self)
{
username = [aDecoder decodeObjectForKey:#"username"];
password = [aDecoder decodeObjectForKey:#"password"];
accData = [aDecoder decodeObjectForKey:#"data"];
}
return self;
}
-(void)encodeWithCoder:(NSCoder *)aCoder
{
[aCoder encodeObject:username forKey:#"username"];
[aCoder encodeObject:password forKey:#"password"];
[aCoder encodeObject:accData forKey:#"data"];
}
#end
LOADING FILE(filePath is given):
NSData *data = [[NSFileManager defaultManager] contentsAtPath:filePath];
if(data != nil)
{
NSArray *arrayFromData = [NSKeyedUnarchiver unarchiveObjectWithData:data];
NSMutableArray *initArray = [NSMutableArray arrayWithArray:arrayFromData];
[Account setAccounts:initArray];
}
else
{
NSMutableArray *accountsInit = [[NSMutableArray alloc] init];
[Account setAccounts:accountsInit];
}
SAVING FILE:
NSArray *accounts = [Account getAccounts];
NSString *filePath = [AppController getFilePath];
NSData *data = [NSKeyedArchiver archivedDataWithRootObject:accounts];
[data writeToFile:filePath atomically:YES];
A few things:
You should not be archiving password data to disk (even if you are encrypting it). That's what the keychain is for. Have a look at SSKeychain for a good wrapper class.
The Key-value coding error you are getting suggests you are trying to reference your serviceData array as just "service" somewhere. Check your valueForKey and setValueForKey statements.
Can you post the rest of the Account class? That method setAccounts looks like it might be relevant.
Also is there a reason you are using Keyed Archiving instead of Core Data?
In my chat application I want to get all online registered users. So everybody and not only people in my roster which is achieved with this code:
- (void)xmppStream:(XMPPStream *)sender didReceivePresence:(XMPPPresence *)presence {
// a buddy went offline/online
NSString *presenceType = [presence type]; // online/offline
NSString *myUsername = [[sender myJID] user];
NSString *presenceFromUser = [[presence from] user];
if (![presenceFromUser isEqualToString:myUsername]) {
if ([presenceType isEqualToString:#"available"]) {
[_chatDelegate newBuddyOnline:[NSString stringWithFormat:#"%##%#", presenceFromUser, #"chat.denederlandsewateren.nl"]];
} else if ([presenceType isEqualToString:#"unavailable"]) {
[_chatDelegate buddyWentOffline:[NSString stringWithFormat:#"%##%#", presenceFromUser, #"chat.denederlandsewateren.nl"]];
}
}
}
With this code the users only sees other users who are 'friends' but I need all users registered on this particular domain. Is this possible with ejabberd?
- (void)getAllRegisteredUsers {
NSError *error = [[NSError alloc] init];
NSXMLElement *query = [[NSXMLElement alloc] initWithXMLString:#"<query xmlns='http://jabber.org/protocol/disco#items' node='all users'/>"
error:&error];
XMPPIQ *iq = [XMPPIQ iqWithType:#"get"
to:[XMPPJID jidWithString:#"DOMAIN"]
elementID:[xmppStream generateUUID] child:query];
[xmppStream sendElement:iq];
}
- (BOOL)xmppStream:(XMPPStream *)sender didReceiveIQ:(XMPPIQ *)iq
{
NSXMLElement *queryElement = [iq elementForName: #"query" xmlns: #"http://jabber.org/protocol/disco#items"];
if (queryElement) {
NSArray *itemElements = [queryElement elementsForName: #"item"];
NSMutableArray *mArray = [[NSMutableArray alloc] init];
for (int i=0; i<[itemElements count]; i++) {
NSString *jid=[[[itemElements objectAtIndex:i] attributeForName:#"jid"] stringValue];
[mArray addObject:jid];
}
}
I had the same issue, I got queryElement as nil as well. I've changed the response code to see the XML like this:
- (BOOL)xmppStream:(XMPPStream *)sender didReceiveIQ:(XMPPIQ *)iq
{
//DDLogVerbose(#"%#: %# - %#", THIS_FILE, THIS_METHOD, [iq elementID]);
//NSXMLElement *queryElement = [iq elementForName:#"query" xmlns: #"http://jabber.org/protocol/disco#items"];
NSXMLElement *queryElement = [iq elementForName:#"query" xmlns: #"jabber:iq:roster"];
NSLog(#"IQ: %#",iq);
if (queryElement) {
NSArray *itemElements = [queryElement elementsForName: #"item"];
NSMutableArray *mArray = [[NSMutableArray alloc] init];
for (int i=0; i<[itemElements count]; i++) {
NSString *jid=[[[itemElements objectAtIndex:i] attributeForName:#"jid"] stringValue];
NSLog(#"%#",jid);
[mArray addObject:jid];
}
}
return NO;
}
As you may see what I've changed is the xmlns: from this xmlns: #"http://jabber.org/protocol/disco#items" to this xmlns: #"jabber:iq:roster" and that gave me the list of users.
I'm using ejabberd, not sure if this works for all the others XMPP servers.
Also I've found that this gave me the list of the "buddy" users, looks like if you want "all" users you need to make the query as an admin user. Please check this link for more information about it: https://www.ejabberd.im/node/3420
After googling, You can not get all user easily, You must need to create Shared Roster Groups by follow step in the Example 1: everybody can see everybody else after done this you will get all the online users in the below delegate methods.
- (void)xmppStream:(XMPPStream *)sender didReceivePresence:(XMPPPresence *)presence
Basically I'm trying to create a chatroom with all registered users on my domain using a ejabberd server. So a user can see all other online registered users on that domain when he enters the chatroom.
Until now I've only been able to make all the users 'friends / buddies' visible and deliver a notification when a friend goes online or offline with the help of the XMPP framework:
- (void)xmppStream:(XMPPStream *)sender didReceivePresence:(XMPPPresence *)presence {
// a buddy went offline/online
NSString *presenceType = [presence type]; // online/offline
NSString *myUsername = [[sender myJID] user];
NSString *presenceFromUser = [[presence from] user];
if (![presenceFromUser isEqualToString:myUsername]) {
if ([presenceType isEqualToString:#"available"]) {
[_chatDelegate newBuddyOnline:[NSString stringWithFormat:#"%##%#", presenceFromUser, #"chat.denederlandsewateren.nl"]];
} else if ([presenceType isEqualToString:#"unavailable"]) {
[_chatDelegate buddyWentOffline:[NSString stringWithFormat:#"%##%#", presenceFromUser, #"chat.denederlandsewateren.nl"]];
}
}
}
I'm able to get a list with all online registered users but I don't know how to notify the user when somebody goes online or offline.
- (void)getAllRegisteredUsers {
xmppRosterMemStorage = [[XMPPRosterMemoryStorage alloc] init];
xmppRoster = [[XMPPRoster alloc] initWithRosterStorage:xmppRosterMemStorage
dispatchQueue:dispatch_get_main_queue()];
[xmppRoster addDelegate:self delegateQueue:dispatch_get_main_queue()];
xmppRoster.autoAcceptKnownPresenceSubscriptionRequests = false;
xmppRoster.autoFetchRoster = true;
[xmppRoster activate:xmppStream];
[xmppRoster fetchRoster];
NSError *error = [[NSError alloc] init];
NSXMLElement *query = [[NSXMLElement alloc] initWithXMLString:#"<query xmlns='http://jabber.org/protocol/disco#items' node='all users'/>"
error:&error];
XMPPIQ *iq = [XMPPIQ iqWithType:#"get"
to:[XMPPJID jidWithString:#"chat.denederlandsewateren.nl"]
elementID:[xmppStream generateUUID] child:query];
[xmppStream sendElement:iq];
}
- (BOOL)xmppStream:(XMPPStream *)sender didReceiveIQ:(XMPPIQ *)iq
{
NSXMLElement *queryElement = [iq elementForName: #"query" xmlns:
#"http://jabber.org/protocol/disco#items"];
if (queryElement) {
NSArray *itemElements = [queryElement elementsForName: #"item"];
NSMutableArray *mArray = [[NSMutableArray alloc] init];
for (int i=0; i<[itemElements count]; i++) {
NSString *jid=[[[itemElements objectAtIndex:i] attributeForName:#"jid"] stringValue];
[mArray addObject:jid];
[xmppRoster addUser:[XMPPJID jidWithString:jid] withNickname:[[jid componentsSeparatedByString:#"#"] objectAtIndex:0]];
}
}
How can I create a chatroom where the user can see all online registered users on one domain using a Ejabberd server and the XMPP framework?
I've been stuck on this one for a while and any advice would be greatly appreciated. I've created a singleton object called SharedUser that represents the user who is currently using the app. This SharedUser object has two NSStrings (for username and userId) and an NSArray (for the company departments to which the user belongs). The user is initialized upon login with a method called initWithUsername. Inside this method the username is used to parse the user and get the user's unique id number and the the user's departments.
My problem is as follows: when I get the user through the sharedUser method at a later point in the app, the userId string is empty and causes an exc_bad_access error when I try to use it. I know that the userId string is being initialized though because I have observed this happening in the debugger. However, strangely enough, the username string still exists for the same object that is lacking the userId string. I'm very confused as to how the memory behind userId could be released while username would still hang around.
My SharedUser class looks like this:
#implementation SharedUser
#synthesize userId;
#synthesize username;
#synthesize departmentIds;
static SharedUser *sharedUser = nil;
+(SharedUser *)sharedUser {
#synchronized(self) {
if (!sharedUser) {
sharedUser=[[self alloc] init];
}
}
return sharedUser;
}
+ (id)allocWithZone:(NSZone *)zone {
#synchronized(self) {
if (sharedUser == nil) {
sharedUser = [super allocWithZone:zone];
return sharedUser;
}
}
return nil;
}
- (id)copyWithZone:(NSZone *)zone {
return self;
}
- (id)retain {
return self;
}
- (unsigned)retainCount {
return NSUIntegerMax;
}
- (oneway void)release {
// never release
}
- (id)autorelease {
//do nothing
}
- (id) init {
#synchronized(self) {
[super init];
username = #"";
userId = #"";
departmentIds = nil;
return self;
}
}
- (void) initWithUserName:(NSString *) loginName {
username = loginName;
//create a request and a connection
NSURL *url = [NSURL URLWithString:#"http://blah.com/url/for/the/json/"];
ASIHTTPRequest *request = [ASIHTTPRequest requestWithURL:url];
[request startSynchronous];
NSError *error = [request error];
if (!error) {
NSString *responseString = [request responseString];
NSArray *listOfPeopleDictionaries = [responseString JSONValue];
for (NSDictionary *personDictionary in listOfPeopleDictionaries) {
if ([loginName isEqualToString:[personDictionary objectForKey:#"username"]]) {
// Set the user id
userId = [personDictionary objectForKey:#"id"];
// Set the user's department
NSArray *departmentsArray = [personDictionary objectForKey:#"organizations"];
for (NSDictionary *department in departmentsArray) {
[departmentIds addObject:[department objectForKey:#"id"]];
}
}
}
}
else {
//give error
}
}
- (void)dealloc {
// Should never be called
[username release];
[userId release];
[departmentIds release];
[super dealloc];
}
The following code would cause an exc_bad_access error on the third line.
SharedUser *user = [SharedUser sharedUser];
NSLog(#"%#", user.username);
NSLog(#"%#", user.userId);
That said, my question is where is the memory behind the userId string being released and what do I do to fix it? I'm brand new to stack overflow so please be gentle.
userId is not being retained by your singleton. The value is owned by personDictionary, which is owned by listOfPeopleDictionaries, which is an autoreleased return value from [responseString JSONValue]. When the autorelease pool is purged the whole chain is released including userId.
The solution is to retain userId, either by doing
userId = [[personDictionary objectForKey:#"id"] retain];
or
self.userId = [personDictionary objectForKey:#"id"]
username has the same issue, but probably isn't crashing as you're holding on to it in the object which is calling initWithUserName:.
I would probably go with another solution: "normal" class, that offers one shared instance, while it doesn't bother about all the memory (non-)management
And I want to propose the new grand central dispatch approach
#implementation User
#synthesize userId;
#synthesize username;
#synthesize departmentIds;
+ (User *)sharedUser {
static User *_sharedUser = nil;
static dispatch_once_t oncePredicate;
dispatch_once(&oncePredicate, ^{
_sharedUser = [[self alloc] init…];
//what ever is needed to get a proper shared user
});
return _sharedUser;
}
#end
More is not needed, if you are ok with a less strict version of a singleton.
This is also much easier to handle in Unit-testing.
User *sharedUser = [User sharedUser];
to fix your code, please try
username = [loginName copy]; //or retain, if you use retain in ur property
instead of
username = loginName;
FBSession.m
- (BOOL)resume {
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
FBUID uid = [[defaults objectForKey:#"FBUserId"] longLongValue];
if (uid) {
NSDate* expirationDate = [defaults objectForKey:#"FBSessionExpires"];
if (!expirationDate || [expirationDate timeIntervalSinceNow] > 0) {
_uid = uid;
_sessionKey = [[defaults stringForKey:#"FBSessionKey"] copy];
_sessionSecret = [[defaults stringForKey:#"FBSessionSecret"] copy];
_expirationDate = [expirationDate retain];
for (id<FBSessionDelegate> delegate in _delegates) {
[delegate session:self didLogin:_uid]; // this is the line where i m getting stuck while looping break
}
return YES;
}
}
return NO;
}
#pragma mark Facebook
- (void)session:(FBSession *)session didLogin:(FBUID)uid{
NSLog(#"Facebook Logged in");
FBStreamDialog *dialog = [[[FBStreamDialog alloc] initWithSession:fbsession] autorelease];
dialog.delegate=self;
Note *note;
NSString *str = [note noteTitle];
dialog.attachment = [NSString stringWithFormat: #"{\"name\" : \"Death Diary Bucket List Item\",\"href\" : \"http://ifidieapp.com\",\"caption\" : \"{*actor*} added a Bucket List Item\",\"description\" : \"%# \",\"media\": [{\"type\": \"image\",\"src\": \"http://deathdiaryapp.com/wp-content/uploads/2010/01/facebook-big-icon.jpg\",\"href\": \"http://ifidieapp.com\"}]}",str];
}
dialog.userMessagePrompt = #"Enter anything about the item here:";
[dialog show];
}
What could be wrong?
not sure why you should have a array of delegate...
if stuck, try the old API:
facebook = [[Facebook alloc] initWithAppId:#"YOUR_APP_ID"];
[facebook dialog:#"stream.publish" andParams:fbArguments andDelegate:self];
easier, faster (for prototyping or light needs.
if you want a specific answer to your issue, please provide more details (where do you initialize your fb object, where do you call FBSession from).