I've lost 2 hours searching the apple developer docs, google, and stackoverflow. Where can I find my project's app_id in Xcode 6?
I am trying to adapt the apple keychain sample code https://developer.apple.com/library/ios/samplecode/GenericKeychain/Listings/ReadMe_txt.html#//apple_ref/doc/uid/DTS40007797-ReadMe_txt-DontLinkElementID_11
but I've never had to use my app_id before. Thanks for any suggestions.
Notes: When you app created in iTunes Connect, apple assigns a app_id to your APP, then you can check it in "More->About This App"
Method: getSecureValueForKey
Method: storeSecureValue
#import "JNYJKeyChain.h"
#implementation JNYJKeyChain
+ (NSString *)getSecureValueForKey:(NSString *)key
{
/*
Return a value from the keychain
*/
// Retrieve a value from the keychain
NSDictionary *result = nil;
NSArray *keys = [[[NSArray alloc] initWithObjects: (NSString *) kSecClass, kSecAttrAccount, kSecReturnAttributes, nil] autorelease];
NSArray *objects = [[[NSArray alloc] initWithObjects: (NSString *) kSecClassGenericPassword, key, kCFBooleanTrue, nil] autorelease];
NSDictionary *query = [[NSDictionary alloc] initWithObjects: objects forKeys: keys];
// Check if the value was found
OSStatus status = SecItemCopyMatching((CFDictionaryRef) query, (CFTypeRef *) &result);
[query release];
if (status != noErr) {
// Value not found
return nil;
} else {
// Value was found so return it
NSString *value = [NSString stringWithString:(NSString *) [result objectForKey: (NSString *) kSecAttrGeneric]];
[result release];
return value;
}
}
+ (BOOL)storeSecureValue:(NSString *)value forKey:(NSString *)key
{
/*
Store a value in the keychain
*/
// Get the existing value for the key
NSString *existingValue = [self getSecureValueForKey:key];
// Check if a value already exists for this key
OSStatus status;
if (existingValue) {
// Value already exists, so update it
NSArray *keys = [[[NSArray alloc] initWithObjects: (NSString *) kSecClass, kSecAttrAccount, nil] autorelease];
NSArray *objects = [[[NSArray alloc] initWithObjects: (NSString *) kSecClassGenericPassword, key, nil] autorelease];
NSDictionary *query = [[[NSDictionary alloc] initWithObjects: objects forKeys: keys] autorelease];
status = SecItemUpdate((CFDictionaryRef) query, (CFDictionaryRef) [NSDictionary dictionaryWithObject:value forKey: (NSString *) kSecAttrGeneric]);
} else {
// Value does not exist, so add it
NSArray *keys = [[[NSArray alloc] initWithObjects: (NSString *) kSecClass, kSecAttrAccount, kSecAttrGeneric, nil] autorelease];
NSArray *objects = [[[NSArray alloc] initWithObjects: (NSString *) kSecClassGenericPassword, key, value, nil] autorelease];
NSDictionary *query = [[[NSDictionary alloc] initWithObjects: objects forKeys: keys] autorelease];
status = SecItemAdd((CFDictionaryRef) query, NULL);
}
// Check if the value was stored
if (status != noErr) {
// Value was not stored
return false;
} else {
// Value was stored
return true;
}
}
#end
Related
I have no problems to get the value of name in terms (name of my blog post category) out of the xmlrpc server response object ...
Server response:
responseArray: (
{ guid = "http://www.domain.com/wp/?p=12";
"post_id" = "123";
terms = (
{ name = "Uncategorized"; }
);
}
)
... with the following lines of Objective-C code:
NSMutableArray *responseArray = [[NSMutableArray alloc] init];
responseArray = [nodeSaveResponse object];
for(i = 0; i < responseArray.count; i++) {
NSString *postLink = [[responseArray objectAtIndex: i] valueForKey: #"guid"];
NSString *postId = [[responseArray objectAtIndex: i] valueForKey: #"post_id"];
NSMutableArray *catArray = [[NSMutableArray alloc] init];
catArray = [[responseArray objectAtIndex: i] valueForKey: #"terms"]];
NSArray *cat = [catArray valueForKey: #"name"];
NSString *myCatString = [cat objectAtIndex: 0];
}
But to send a new blog post fails because the following code to pack the category string is somehow wrong:
NSString *myCatString = #"MyCategory";
NSMutableDictionary *name = [[NSMutableDictionary dictionaryWithObjectsAndKeys: myCatString, #"name", nil];
NSMutableArray *catArray = [[NSMutableArray arrayWithObject: name];
NSMutableDictionary *values = [[NSMutableDictionary alloc] init];
[values setObject: title forKey: #"post_title"];
// and so on with other values - until here everything works well
[values setObject: catArray forKey: #"terms"]; // if this line is called, the request fails
NSArray *params = [NSArray arrayWithObjects: #"1", user, pass, values, nil];
[myRequest setMethod: #"wp.newPost" withParameter: params];
Any idea, where my fault is?
Cheers, Martin
In my code, I set array inside a NSMutableDictionary as
if (array.count > 0) {
[self.filters setValue:array forKey:[self getKey:[[NSNumber numberWithInt:indexPath.section] intValue]]];
}
where array is
NSMutableArray *array = [[NSMutableArray alloc] init];
When the receiving code receives it, I tried to join the values in array as
if ([item objectForKey:#"category_filter"] != nil) {
NSArray *array = [NSArray arrayWithObjects:[item objectForKey:#"category_filter"], nil];
NSString *categories = [array componentsJoinedByString:#","];
NSLog(#"value:%#", categories);
}
where item is (NSMutableDictionary *)item
When I see log, I see as
2014-06-24 17:43:12.520 yelp[69744:70b] value:(
"Bagels (bagels)",
"Bakeries (bakeries)"
)
so they are not joined yet. What am I doing wrong here?
As Hot Licks commented,
I had to make change as
NSArray *array = [NSArray arrayWithArray:[item objectForKey:#"category_filter"]];
instead of
NSArray *array = [NSArray arrayWithObjects:[item objectForKey:#"category_filter"]];
UPDATE
Whenever I comment out these lines writeToFile will create a file but if I dont,it will not work.
Here is my code..
NSMutableDictionary *allData = [[NSMutableDictionary alloc] init];
NSArray *countries = [self retrieveCountries];
for(NSDictionary *dicCountry in countries){
NSString *countryName = [dicCountry objectForKey:#"en_name"];
NSArray *capital = [self retrieveCapitals:countryName];
NSMutableDictionary *capitalInfo = [[NSMutableDictionary alloc] init];
for(NSDictionary *dictPerCap in capital){
NSString *cap = [dictPerCap objectForKey:#"en_name"];
NSArray *items = [self retrieveItems:cap];
NSArray *categories = [self retrieveCategories:cap];
if(items == nil)
items = [[NSArray alloc] init];
if(categories == nil)
categories = [[NSArray alloc] init];
// store data in a dictionary
NSDictionary* tempCapDic = [NSDictionary dictionaryWithObjectsAndKeys:
items, #"items",
categories, #"categories",
nil];
//store
[capitalInfo setObject:tempCapDic forKey:cap];
}
// store data in a dictionary
NSDictionary* dataDic = [NSDictionary dictionaryWithObjectsAndKeys:
capital, #"capitals",
capitalInfo, #"info",
nil];
//store
[allData setObject:dataDic forKey:countryName];
}
/**************************/
NSDictionary *rootDict = [NSDictionary dictionaryWithObjectsAndKeys:countries, #"detailedCountries", allData, #"all", nil];
The lines that needs to be commented out inorder to work are:
capital, #"capitals",
capitalInfo, #"info",
in NSDictionary* tempCapDic.
Any idea on how to fix this?
I'm using the following code:
+ (void)createKeychainItem:(NSString *)name
{
// Don't create if one already exists
if ([self getKeychainItem:name] != nil) return;
NSData *encodedName = [name dataUsingEncoding:NSUTF8StringEncoding];
NSDictionary *attributes = #{
(id)kSecAttrAccount : encodedName,
(id)kSecAttrGeneric : encodedName,
(id)kSecAttrLabel : name,
(id)kSecAttrService : name,
(id)kSecClass : (id)kSecClassGenericPassword,
};
OSStatus result = SecItemAdd((CFDictionaryRef)attributes, NULL);
}
+ (NSDictionary *)getKeychainItem:(NSString *)name
{
// Build the query
NSData *encodedName = [name dataUsingEncoding:NSUTF8StringEncoding];
NSDictionary *query = #{
(id)kSecAttrAccount : encodedName,
(id)kSecAttrGeneric : encodedName,
(id)kSecAttrService : name,
(id)kSecClass : (id)kSecClassGenericPassword,
(id)kSecMatchLimit : (id)kSecMatchLimitOne,
(id)kSecReturnAttributes : (id)kCFBooleanTrue,
};
NSDictionary *output = nil;
OSStatus result = SecItemCopyMatching((CFDictionaryRef)query, (CFTypeRef *)&output);
// Convert the password if it exists
NSData *passwordData = [output objectForKey:kSecValueData];
if (passwordData != nil) {
NSMutableDictionary *mutableOutput = [[output mutableCopy] autorelease];
NSString *password = [[[NSString alloc] initWithBytes:passwordData length:passwordData.length encoding:NSUTF8StringEncoding] autorelease];
[mutableOutput setObject:password forKey:(id)kSecValueData];
output = [[mutableOutput copy] autorelease];
}
return output;
}
+ (void)updateKeychainItem:(NSString *)name value:(NSString *)value attribute:(id)attribute
{
// Get the item
NSDictionary *values = [self getKeychainItem:name];
// If we got nothing back, build it
if (values == nil) {
[self createKeychainItem:name];
}
// Create a query to update
NSData *encodedName = [name dataUsingEncoding:NSUTF8StringEncoding];
NSDictionary *query = #{
(id)kSecAttrAccount : encodedName,
(id)kSecAttrGeneric : encodedName,
(id)kSecAttrService : name,
(id)kSecClass : (id)kSecClassGenericPassword,
};
NSDictionary *attributes = nil;
if (attribute == kSecValueData) {
attributes = #{ (id)kSecValueData : [value dataUsingEncoding:NSUTF8StringEncoding] };
} else {
attributes = #{ attribute : value };
}
OSStatus result = SecItemUpdate((CFDictionaryRef)query, (CFDictionaryRef)attributes);
}
Setting a value with [self updateKeychainItem:AuthTokenIdentifer value:authToken attribute:kSecValueData]; works and I can see it in Keychain Access.
Fetching the results with NSDictionary *values = [self getKeychainItem:AuthTokenIdentifer]; works, but the kSecValueData is not set in the dictionary. Everything else is set, like the create and modified dates, just not the secure data.
Any ideas? This happens on iOS and Mac.
You need to use the attributes dictionary from getKeychainItem: to fetch the value. Something like
NSMutableDictionary *dataQuery = [attrs mutableCopy];
[dataQuery setObject:(__bridge id)kCFBooleanTrue forKey:(__bridge id)kSecReturnData];
[dataQuery setObject:(__bridge id)kSecClassGenericPassword forKey:(__bridge id)kSecClass];
CFTypeRef resultData;
OSStatus status = SecItemCopyMatching((__bridge CFDictionaryRef)(dataQuery), &resultData);
NSData *tokenData = CFBridgingRelease(resultData);
Nesting means taking an array of key value pairs and grouping them hierarchically by a specified key. See this page for examples: http://bl.ocks.org/d/3176159/. If not, I'll just try to port https://github.com/mbostock/d3/blob/master/src/core/nest.js over but I don't want to reinvent the wheel.
This is the answer that I came up with. Let me know if you have suggestions for improvements.
// Wrapper method
// keys are in order of hierarchy
- (NSMutableArray *)nestArray:(NSArray *)array withKeys:(NSArray *)keys
{
return [self nestArray:array withKeys:keys depth:0];
}
// Private
// Assumes arrays of dictionaries with strings as the entries.
- (NSMutableArray *)nestArray:(NSArray *)array withKeys:(NSArray *)keys depth:(int)depth
{
// Current key
NSString *key = [keys objectAtIndex:depth];
depth++;
// Create dictionary of the keys
NSMutableDictionary *map = [[NSMutableDictionary alloc] init];
for (NSDictionary *dictionary in array) {
NSString *value = [dictionary objectForKey:key];
if ([map objectForKey:value]) {
[[map objectForKey:value] addObject:dictionary];
} else {
[map setObject:[NSMutableArray arrayWithObject:dictionary] forKey:value];
}
}
NSMutableArray *nest = [[NSMutableArray alloc] init];
for (NSString *valkey in [map allKeys]) {
NSMutableArray *values = [map objectForKey:valkey];
if (depth < keys.count) {
values = [self nestArray:[NSArray arrayWithArray:array] withKeys:keys depth:depth];
}
NSMutableDictionary *dictionary = [NSMutableDictionary dictionaryWithObjectsAndKeys:valkey,#"key",values,#"values", nil];
[nest addObject:dictionary];
}
return nest;
}