KeychainWrapper Objective C Identifier and Key questions - objective-c

I’m new to both in app purchases and using the keychain. I am using Objective C and KeychainItemWrapper.
For now I want to simply store a number in the keychain. I don’t want anyone outside the app to be able to change it, and while I don’t much care if anyone can see it, I would like to understand what’s encrypted and what’s not as I may want to store private data later.
I have successfully stored a number and retrieved, even after deleting and reinstalling the app, but I’m not at all sure I’m doing it right. How does one choose an identifier and which keys are appropriate?
As you’ll see, I’m pretty unclear on the concepts.
First question: What is the “identifier” and why can’t I use more than one?
Here’s the code:
#property (nonatomic, strong) KeychainItemWrapper *myChain;
. . .
if (myChain == nil)
{
// first question: what identifier should I use?
myChain = [[KeychainItemWrapper alloc] initWithIdentifier:#"test" accessGroup:nil];
}
So once I’ve used the identifier “test”, it appears that I’m stuck with it on this phone. If I use any other value then KeychainItemWrapper fails “unable to add item”. I don’t understand this at all. How do I create different identifiers? Do I want to or need to? What exactly is this identifying?
Moving on to storing. Per the code below, I can store a number, description and comment.
// storing:
// let’s start with the number 10
NSString *testNum = #"10";
NSString *testDescr = #"this is a line of text";
[myChain setObject:testDescr forKey:(__bridge id)(kSecAttrDescription)];
[myChain setObject:testNum forKey:(__bridge id)(kSecValueData)];
[myChain setObject:#"This is a comment" forKey:(__bridge id)(kSecAttrComment)];
// retrieving:
NSString *descOut = [myChain objectForKey: (__bridge id)kSecAttrDescription];
NSData *numberOut = [myChain objectForKey: (__bridge id)(kSecValueData)];
And this all works fine.
But what are the appropriate keys for this usage? I just picked a few at random for testing.
Thank you, I know I’m asking a lot, but I’ve been through the docs and stack overflow and various tutorials and I haven’t really got a good understanding of this.

Related

Unique Instances of NSString for empty or 1-char strings

I would like to understand more about the way XCode/Objective-C handle constant strings. I found a related question, but I would like more information. Consider the following code:
NSString *a = [[NSString alloc] initWithUTF8String:[[_textFieldA stringValue] UTF8String]];
NSString *b = [[NSString alloc] initWithUTF8String:[[_textFieldB stringValue] UTF8String]];
NSString *c = [a copy];
NSString *d = [a mutableCopy];
Note that the textFields are just a way to set the strings at runtime ensuring that the compiler doesn't get too smart on me and build in a single instance.
If my text fields are empty, or contain a single character such as "x" or "$", then a == b == c == the same constant NSString instance. If I instead provide "xy", then a == c != b. d is always unique, as one might expect since it is mutable.
Now normally this wouldn't be an issue, I'm not trying to modify the contents of these strings, however, I am working on a system where I frequently use objc_setAssociatedObject. So here now I might come accross an empty string, and then set associated object data on it, and then have another empty string and collide with the first.
I have, for the moment, solved my issue by creating mutable strings instead.
So my questions:
Is this an Objective-C specification, or an XCode excentricity?
Does anyone know how the instance is determined? Why "x" get's one instance, but not "xy"? I would think some internal dictionary is involved and there's no good reason to stop at 1 character.
Is there a way to turn this off, so all empty strings are unique instances, or other suggestions?
I am using XCode 5.1.1, OSX 10.9.4, SDK 10.9.
Thank you!
Is this an Objective-C specification, or an XCode excentricity?
It is just implementation detail. Not documented any where. These kind of behaviour may changed in future without notice.
Does anyone know how the instance is determined? Why "x" get's one instance, but not "xy"? I would think some internal dictionary is involved and there's no good reason to stop at 1 character.
No until someone able to access source code want to share the details with us.
Is there a way to turn this off, so all empty strings are unique instances, or other suggestions?
No way to turn it off. Don't use objc_setAssociatedObject with NSString
As #Ken Thomases said in comment
In general, it probably doesn't make sense to use objc_setAssociatedObject() with any value class.
Some other examples are NSNumber, NSData and NSValue. They are often cached and reused.

iOS keychain, store more kSecValueData items

I am using a keychainwrapper which works with ARC, and with this you can store a password into the keychain with the following code:
[keychainItem setObject:InputField.text forKey:(__bridge id)(kSecValueData)];
And get it out with:
NSString *loc_pwd1 = [keychainItem objectForKey:(__bridge NSString*)kSecValueData];
As I understand the kSecValueData means that the value will be encrypted, but what if I wanna store more encrypted values, can you store with some kind of identifier, so you can have several kSecValueData elements.
Thanks
Your key is associated to one entry in the keychain. You could store an NSDictionary or NSArray (depending of your situation) instead of directly storing the inputField.text. So if you need to add more values to the object of that key, you would simply have to add it to the dictionary/array.
I also recently used the iOS keychain, and I picked up SSKeychain, it looks a bit more straightforward than yours, worth a look! (I'm not saying the one you use is bad, just letting you know what worked for me :P)

Using libqrencode library

I loaded libqrencode library in my cocoa project but I'm not sure how to use it exactly. I have a text field in which you type a text, and once done you click a button and I log that text with NSLog. Now I want to encode that text to be able to use it later and generate a QRcode out of it, so in the manual it's saying to use this format
QRcode* QRcode_encodeString (const char * string,
int version,
QRecLevel level,
QRencodeMode hint,
int casesensitive
)
I am not sure how to use that in my method to log the results as well
- (IBAction)GenerateCode:(id)sender {
NSString *urlText = [[NSString alloc] initWithFormat:#"%#", [_urlField stringValue]];
NSLog(#"The url is %#", urlText);
}
You need to get from an NSString instance to a const char *. This has been answered several times on SO, but here's one. Once you do that, you can call QRCode_encodeString() directly and pass whatever you desire for the arguments.
If you need more specifics, you'll have to try something, post your code, and describe how it's not working for you so we can help you more directly without just writing it for you.

How to use ios 6 challenge in game centre

Firstly,
I am fairly new to objective c / xcode dev so there is a good chance i am being a muppet. I have written a few simple apps to try things and my most recent one has been testing the gamecentre classes / functionality.
i have linked ok to leaderboards and achievements - but i can't get challenges working.
I have added the following code.... which is in my .m
GKLeaderboard *query = [[GKLeaderboard alloc] init];
query.category = LoadLeaderboard;
query.playerScope = GKLeaderboardPlayerScopeFriendsOnly;
query.range = NSMakeRange(1,100);
[query loadScoresWithCompletionHandler:^(NSArray *scores, NSError *error)
{NSPredicate *filter = [NSPredicate predicateWithFormat:#"value < %qi", scoreint];
NSArray *lesserScores = [scores filteredArrayUsingPredicate:filter];
[self presentChallengeWithPreselectedScores: lesserScores];
}
];
this code is basically taken from apple, just replacing the variable names....
this however gives an error on
[self presentChallengeWithPreselectedScores: lesserScores];
error Implicit conversion of an Objective-C pointer to 'int64_t *' (aka 'long long *') is disallowed with ARC
LoadLeaderboard is defined as a string
scoreint is defined as integer, thought this may be issue as not int64_t but that does not seem to make a difference.
I am sure for someone who has any kind of a clue this is a straightforward fix. But i am struggling at the moment. So if anyone can be kind and help a fool in need it would be most appreciated
Thanks,
Matt
welcome to Stack Overflow. I don't know your implementation of presentChallengeWithPreselectedScores method so I can't tell (although it looks like the method is taking a 64 bit integer and you're trying to feed it an array).
There are two ways to issue challenges:
1 - This is the easier way - if you've successfully implemented leader boards and score posting to game center, the challenges work out of the box in iOS6, the user can always view the leader board - select a submitted score (or a completed achievement) and select "Challenge Friend".
2 - The second way is to build a friend picker and let the user issue challenges within your game. But considering you're new to objective-c and game center, it's not so easy. But for your reference here is how you do it:
when you submit a GKScore object for the leaderboards - you can retain and use that GKScore object (call it myScoreObject) like this:
[myScoreObject issueChallengeToPlayers:selectedFriends message:yourMessage];
where selectedFriends is an NSArray (the friend picker should generate this) - the message is optional and can be used only if you want to send a message to challenged friends.

Preferred way of storing data in OS X/Cocoa? [duplicate]

This question already has answers here:
Closed 11 years ago.
Possible Duplicate:
iOS store just a little bit of data
New OS X dev here. I have a modicum of user data I need to store (just paths to recently opened files, really). What is the preferred way of storing these in Cocoa land? I've heard of Core Data before but, as a Windows dev who has encountered tons of APIs from MS like this, does anyone actually use this?
I could just write everything to my own file, of course, but I'd prefer to do things The Right Way(TM).
Any suggestions would be great!
If your application is document based, the list of recently opened files is automatically stored for you. If you need to store them yourself, then I would suggest using NSUserDefaults. It is the most common way to store lightweight information such as preferences and recently used items.
Yes, people do use core data, but it is usually used for more complex data, such as a document with different parts.
See my answer to this thread for five suggestions for storing data. Although that thread covers iOS and therefore Cocoa Touch instead of Cocoa, the answers are all pretty much the same.
Note that the first answer, NSUserDefaults, is meant for saving data like app preferences. That might be most appropriate if the application will always want to load the same set of data; if the data is more like a document, where you might have different sets of data stored in different files, you should use one of the other methods. Writing a property list would probably be simplest in this case:
// store some words in an array and write to a file at pathToFile
NSMutableArray *array = [NSMutableArray array];
[array addObjects: #"foo", #"bar", #"baz", nil];
[array writeToFile:pathToFile];
// (later) read contents of the file at pathToFile into a new array
NSArray *words = [NSArray arrayWithContentsOfFile:pathToFile];
As for Core Data, yes, many people use it. It's a very nice way to manage persistent objects. However, it sounds like it's way more than you need for just storing a bunch of paths.
As ughoavgfhw mentioned, the NSDocument architecture already takes care of keeping a list of recent documents. (If you look through your Preferences folder, the *.LSSharedFileList.plist preference files hold this data).
If you take a look at those files in Property List Editor or Xcode 4, you'll see the preferred way to store a reference to a file in a persistent manner is to use Alias (or "Bookmark") data. If you're coming from a Windows/*nix background, alias data can keep track of an item even if it's renamed or moved.
If you need to store a list of recent files by yourself, and can require OS X 10.6+, you can use NSUserDefaults, along with the bookmark data functionality found in NSURL.
In your method that opens files, you could do something like this:
NSString * const MDRecentDocumentsKey = #"MDRecentDocuments";
- (void)application:(NSApplication *)sender openFiles:(NSArray *)filenames {
// assume single item
NSURL *URL = [NSURL fileURLWithPath:[filenames objectAtIndex:0]];
NSMutableArray *recentAppBookmarks =
[[[[NSUserDefaults standardUserDefaults] objectForKey:MDRecentDocumentsKey]
mutableCopy] autorelease];
// assume 20 item limit
if ([recentAppBookmarks count] + 1 > 20) {
[recentAppBookmarks removeLastObject];
}
NSData *data = [ bookmarkDataWithOptions:0 includingResourceValuesForKeys:nil
relativeToURL:nil error:NULL];
[recentAppBookmarks insertObject:data atIndex:0];
[[NSUserDefaults standardUserDefaults] setObject:recentAppBookmarks
forKey:MDRecentDocumentsKey];
}
To get the list of recent files at app launch, you could do something like this:
- (void)awakeFromNib {
recentAppURLs = [[NSMutableArray alloc] init];
NSArray *recentAppBookmarks =
[[NSUserDefaults standardUserDefaults] objectForKey:MDRecentDocumentsKey];
for (NSData *bookmarkData in recentAppBookmarks) {
NSURL *resolvedURL = [NSURL URLByResolvingBookmarkData:bookmarkData
options:NSURLBookmarkResolutionWithoutUI|NSURLBookmarkResolutionWithoutMounting
relativeToURL:nil bookmarkDataIsStale:NULL error:NULL];
if (resolvedURL) [recentAppURLs addObject:resolvedURL];
}
}
Otherwise, if you need compatibility with OS X 10.5 and earlier, I posted some categories on NSString in this answer.