I'm not entirely sure what
NSString * fileName = [self cachedFileNameForKey:[urlString componentsSeparatedByString:#"?"][0]];
Means from this code. I am primely writing in Swift so this notation is a bit confusing for me. What does the double [ ] notation mean? 3d array?
+ (AVPlayerItem *)localDownloadedVideoFromUrl:(NSURL *)url {
NSString * urlString = url.absoluteString;
NSString * fileName = [self cachedFileNameForKey:[urlString componentsSeparatedByString:#"?"][0]];
TWRDownloadManager * manager = [TWRDownloadManager sharedManager];
if ([manager fileExistsWithName:fileName]) {
AVPlayerItem * item = [AVPlayerItem playerItemWithURL:[NSURL fileURLWithPath:[manager localPathForFile:fileName]]];
return item;
}
return [NSNull null];
}
[] in objective-c is not only used to access arrays, but also used to call methods. Surprising, isn't it?
In general,
[xxx someMethod];
is equivalent to:
xxx.someMethod()
in swift.
So here:
[urlString componentsSeparatedByString:#"?"][0]
means
urlString.components(separatedBy: "?")[0] // "[0]" can also be replaced by ".first", which is safer.
This is then passed to the cachedFileNameForKey as a parameter.
In Swift
var urlString: String = "Know someone who can answer? Share a link to this" // Example string or url.absoluteString
let fileName = urlString.components(separatedBy: "?")
print(fileName)
let string1 = fileName[0]
let string2 = fileName[1]
Hope will helpful to you
Ahh so mistake on my part is that I didn't see what the method -cacheFileNameForKey: was doing.
+ (nullable NSString *)cachedFileNameForKey:(nullable NSString *)key {
const char *str = key.UTF8String;
if (str == NULL) {
str = "";
}
unsigned char r[CC_MD5_DIGEST_LENGTH];
CC_MD5(str, (CC_LONG)strlen(str), r);
NSString *filename = [NSString stringWithFormat:#"%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%#",
r[0], r[1], r[2], r[3], r[4], r[5], r[6], r[7], r[8], r[9], r[10],
r[11], r[12], r[13], r[14], r[15], [key.pathExtension isEqualToString:#""] ? #"" : [NSString stringWithFormat:#".%#", key.pathExtension]];
return filename;
}
I guess its used for a function to generate a file name for a temporary movie file.
Related
I am on OSX, Objective-C.
I have a path/NSURL like
/Users/xxx/Desktop/image2.png
But i pass it to a third party application that excpects finder pathes like
Harddisk:Users:Desktop:image2.png
Is there any method (i can't find) to convert pathes like that or get them out of an NSURL (if possible without string modifying)?
In AppleScript it is
return POSIX file "/Users/xxx/Desktop/image2.png" --> Harddisk:Users:xxx:Desktop:image2.png
EDIT: This is pretty much the same: Cocoa path string conversion
Unfortunately, the method is deprecated...
There is no (easy) alternative at the moment.
The function CFURLCopyFileSystemPath is not deprecated, only the enum case kCFURLHFSPathStyle is deprecated but the raw value 1 is still working and avoids the warning.
I'm using this category of NSString
#implementation NSString (POSIX_HFS)
- (NSString *)hfsPathFromPOSIXPath
{
CFStringRef hfsPath = CFURLCopyFileSystemPath((CFURLRef)[NSURL fileURLWithPath:self], 1);
return (NSString *)CFBridgingRelease(hfsPath);
}
#end
The function works also in Swift. The Swift version is a bit more sophisticated and adds the trailing semicolon representing a dictionary implicitly, here as an extension of URL:
extension URL {
func hfsPath() -> String?
{
if let cfpathHFS = CFURLCopyFileSystemPath(self as CFURL, CFURLPathStyle(rawValue: 1)!) { // CFURLPathStyle.CFURLHFSPathStyle)
let pathHFS = cfpathHFS as String
do {
let info = try self.resourceValues(forKeys: [.isDirectoryKey, .isPackageKey])
let isDirectory = info.isDirectory!
let isPackage = info.isPackage!
if isDirectory && !isPackage {
return pathHFS + ":" // directory, not package
}
} catch _ {}
return pathHFS
}
return nil
}
}
Vadians answer is better than this one - but if vadians method is deprecated, this will be an alternative. Idea is to use applescripts methods to get HFS path called easily with an osascript from an NSString category.
NSString category (credits: https://stackoverflow.com/a/19014463/4591992)
#implementation NSString (ShellExecution)
- (NSString*)runAsCommand {
NSPipe* pipe = [NSPipe pipe];
NSTask* task = [[NSTask alloc] init];
[task setLaunchPath: #"/bin/sh"];
[task setArguments:#[#"-c", [NSString stringWithFormat:#"%#", self]]];
[task setStandardOutput:pipe];
NSFileHandle* file = [pipe fileHandleForReading];
[task launch];
NSString* result = [[NSString alloc] initWithData:[file readDataToEndOfFile] encoding:NSUTF8StringEncoding];
return result;
}
#end
Usage for this case:
NSString* posixToHFS = [NSString stringWithFormat:#"osascript -e 'POSIX file \"%#\" as text'",filePath];
filePath = [posixToHFS runAsCommand];
In my own testing (on 10.13.6, 10.14.6 and 10.15b7), #vadian's solution doesn't work with paths where a folder name component contains a "/" (when viewed in Finder), which then appears as a ":" in a POSIX path and as a "/" in a HFS path.
Demonstration of the bug
Here's a quick test program that you can build by creating a new "command line" project in Xcode:
#import <Foundation/Foundation.h>
int main(int argc, const char * argv[]) {
#autoreleasepool {
NSString *posixPath = #"/EndsInSlash:";
NSURL *url = [NSURL fileURLWithPath:posixPath];
if (url == nil) {
NSLog(#"Oops, this went wrong");
} else {
CFStringRef hfsPath = CFURLCopyFileSystemPath((CFURLRef)url, 1);
NSString *res = (NSString *)CFBridgingRelease (hfsPath);
NSLog(#"HFS path: <%#>", res);
}
}
return 0;
}
When you run it, you'll probably see a correct result printed, i.e. a path that ends in "/". However, that only works if the folder does not exist. So, create a folder named "EndsInSlash/" (not a file!) in your root folder and run the app again - now the resulting path does not end in "/" any more as it should.
Work-around
Below is a "smart" function that uses the faster CFURLCopyFileSystemPath() function whenever possible, i.e. unless a ":" appears in the POSIX path - in which case it performs the conversion on its own, by splitting up the POSIX path into its components, converting them individually (replacing ":" into "/"), prepending the volume name and then merging the components again. This appears to work fine even on macOS 10.15 (Catalina), despite the deprecation warnings.
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
static NSString* stringWithHFSUniStr255(const HFSUniStr255* hfsString)
{
CFStringRef stringRef = FSCreateStringFromHFSUniStr(nil, hfsString);
NSString* result = CFBridgingRelease(stringRef);
return result;
}
NSString* hfsPathFromPOSIXPath (NSString *posixPath)
{
if (posixPath == nil) return #"";
if ([posixPath containsString:#":"]) {
// slow version, but can handle ":" appearing in path components
NSString *result = nil;
FSRef ref;
Boolean isDir;
if (FSPathMakeRef ((const UInt8*)posixPath.UTF8String, &ref, &isDir) == noErr) {
HFSUniStr255 elemName;
FSCatalogInfo catInfo;
NSMutableArray<NSString*> *elems = [NSMutableArray arrayWithCapacity:16];
while (FSGetCatalogInfo (&ref, kFSCatInfoNodeID, &catInfo, &elemName, nil, &ref) == noErr) {
[elems insertObject: stringWithHFSUniStr255(&elemName) atIndex:0];
if (catInfo.nodeID == 2) break;
}
result = [elems componentsJoinedByString:#":"];
}
return result;
} else {
// see https://stackoverflow.com/a/45085776/43615
NSURL *url = [NSURL fileURLWithPath:posixPath];
if (url == nil) {
// could not convert because the path doesn't exist
return nil;
}
CFStringRef hfsPath = CFURLCopyFileSystemPath((CFURLRef)url, kCFURLHFSPathStyle);
return (NSString *)CFBridgingRelease (hfsPath);
}
}
#pragma clang diagnostic pop
See also
Discussion of a related bug with AppleScript, with a work-around: https://forum.latenightsw.com/t/xxx/2097
Bug report filed with Apple: http://www.openradar.me/radar?id=4994410022436864
Objective-C offers runtime reflections feature. I'm trying to find getter/setter selector name of a declared property. I know the basic rule like field/setField:. Anyway I think runtime reflection should offer a feature to resolve the name for complete abstraction, but I couldn't find the function.
How can I resolve the getter/setter method selector (not implementation) of a declared property with runtime reflection in Objective-C (actually Apple's Cocoa)
Or reverse query. (method selector → declared property)
I think you can get the selector names only if the property is declared with explicit (setter = XXX and/or getter = XXX)
So to get the getter and setter selector names for some property 'furType' of the class 'Cat':
objc_property_t prop = class_getProperty([Cat class], "furType");
char *setterName = property_copyAttributeValue(prop, "S");
if (setterName == NULL) { /*Assume standard setter*/ }
char *getterName = property_copyAttributeValue(prop, "G");
if (getterName == NULL) { /*Assume standard getter */ }
I don't know of a reverse query, other than iterating through all the properties and looking for matches. Hope that helps.
A little update from my NSObject category. Hope this'll help some one:
+(SEL)getterForPropertyWithName:(NSString*)name {
const char* propertyName = [name cStringUsingEncoding:NSASCIIStringEncoding];
objc_property_t prop = class_getProperty(self, propertyName);
const char *selectorName = property_copyAttributeValue(prop, "G");
if (selectorName == NULL) {
selectorName = [name cStringUsingEncoding:NSASCIIStringEncoding];
}
NSString* selectorString = [NSString stringWithCString:selectorName encoding:NSASCIIStringEncoding];
return NSSelectorFromString(selectorString);
}
+(SEL)setterForPropertyWithName:(NSString*)name {
const char* propertyName = [name cStringUsingEncoding:NSASCIIStringEncoding];
objc_property_t prop = class_getProperty(self, propertyName);
char *selectorName = property_copyAttributeValue(prop, "S");
NSString* selectorString;
if (selectorName == NULL) {
char firstChar = (char)toupper(propertyName[0]);
NSString* capitalLetter = [NSString stringWithFormat:#"%c", firstChar];
NSString* reminder = [NSString stringWithCString: propertyName+1
encoding: NSASCIIStringEncoding];
selectorString = [#[#"set", capitalLetter, reminder, #":"] componentsJoinedByString:#""];
} else {
selectorString = [NSString stringWithCString:selectorName encoding:NSASCIIStringEncoding];
}
return NSSelectorFromString(selectorString);
}
I need a quick and easy way to store files with unique file names on iOS. I need to prefix the file with a string, and then append the generated unique identifier to the end. I was hoping NSFileManager had some convenient method to do this, but I can't seem to find it.
I was looking at createFileAtPath:contents:attributes:, but am unsure if the attributes will give me that unique file name.
Create your own file name:
CFUUIDRef uuid = CFUUIDCreate(NULL);
CFStringRef uuidString = CFUUIDCreateString(NULL, uuid);
CFRelease(uuid);
NSString *uniqueFileName = [NSString stringWithFormat:#"%#%#", prefixString, (NSString *)uuidString];
CFRelease(uuidString);
A simpler alternative proposed by #darrinm in the comments:
NSString *prefixString = #"MyFilename";
NSString *guid = [[NSProcessInfo processInfo] globallyUniqueString] ;
NSString *uniqueFileName = [NSString stringWithFormat:#"%#_%#", prefixString, guid];
NSLog(#"uniqueFileName: '%#'", uniqueFileName);
NSLog output:
uniqueFileName: 'MyFilename_680E77F2-20B8-444E-875B-11453B06606E-688-00000145B460AF51'
Note: iOS6 introduced the NSUUID class which can be used in place of CFUUID.
NSString *guid = [[NSUUID new] UUIDString];
Super-easy Swift 4 1-liner:
fileName = "MyFileName_" + UUID().uuidString
or
fileName = "MyFileName_" + ProcessInfo().globallyUniqueString
I use current date to generate random file name with a given extension. This is one of the methods in my NSFileManager category:
+ (NSString*)generateFileNameWithExtension:(NSString *)extensionString
{
// Extenstion string is like #".png"
NSDate *time = [NSDate date];
NSDateFormatter* df = [NSDateFormatter new];
[df setDateFormat:#"dd-MM-yyyy-hh-mm-ss"];
NSString *timeString = [df stringFromDate:time];
NSString *fileName = [NSString stringWithFormat:#"File-%#%#", timeString, extensionString];
return fileName;
}
You can also use the venerable mktemp() (see man 3 mktemp). Like this:
- (NSString*)createTempFileNameInDirectory:(NSString*)dir
{
NSString* templateStr = [NSString stringWithFormat:#"%#/filename-XXXXX", dir];
char template[templateStr.length + 1];
strcpy(template, [templateStr cStringUsingEncoding:NSASCIIStringEncoding]);
char* filename = mktemp(template);
if (filename == NULL) {
NSLog(#"Could not create file in directory %#", dir);
return nil;
}
return [NSString stringWithCString:filename encoding:NSASCIIStringEncoding];
}
The XXXXX will be replaced with a unique letter/number combination. They can only appear at the end of the template, so you cannot have an extension appended in the template (though you can append it after the unique file name is obtained). Add as many X as you want in the template.
The file is not created, you need to create it yourself. If you have multiple threads creating unique files in the same directory, you run the possibility of having race conditions. If this is the case, use mkstemp() which creates the file and returns a file descriptor.
In iOS 6 the simplest method is to use:
NSString *uuidString = [[NSUUID UUID] UUIDString];
Here is what I ended up using in Swift 3.0
public func generateUniqueFilename (myFileName: String) -> String {
let guid = ProcessInfo.processInfo.globallyUniqueString
let uniqueFileName = ("\(myFileName)_\(guid)")
print("uniqueFileName: \(uniqueFileName)")
return uniqueFileName
}
Swift 4.1 and 5. Just pass you file extension name and function will return unique file name.
func uniqueFileNameWithExtention(fileExtension: String) -> String {
let uniqueString: String = ProcessInfo.processInfo.globallyUniqueString
let formatter = DateFormatter()
formatter.dateFormat = "yyyyMMddhhmmsss"
let dateString: String = formatter.string(from: Date())
let uniqueName: String = "\(uniqueString)_\(dateString)"
if fileExtension.length > 0 {
let fileName: String = "\(uniqueName).\(fileExtension)"
return fileName
}
return uniqueName
}
This should probably work for you:
http://vgable.com/blog/2008/02/24/creating-a-uuid-guid-in-cocoa/
The author of the post suggests implementing a 'stringWithUUID' method as a category of NSString. Just append a GUID generated with this method to the end of the file name that you're creating.
Swift 4.2, I use two options, one mostly unique but readable, and the other just unique.
// Create a unique filename, added to a starting string or not
public func uniqueFilename(filename: String = "") -> String {
let uniqueString = ProcessInfo.processInfo.globallyUniqueString
return filename + "-" + uniqueString
}
// Mostly Unique but Readable ID based on date and time that is URL compatible ("unique" to nearest second)
public func uniqueReadableID(name: String = "") -> String {
let timenow = DateFormatter.localizedString(from: Date(), dateStyle: .medium, timeStyle: .medium)
let firstName = name + "-" + timenow
do {
// Make ID compatible with URL usage
let regex = try NSRegularExpression(pattern: "[^a-zA-Z0-9_]+", options: [])
let newName = regex.stringByReplacingMatches(in: firstName, options: [], range: NSMakeRange(0, firstName.count), withTemplate: "-")
return newName
}
catch {
print("🧨 Unique ID Error: \(error.localizedDescription)")
return uniqueFilename(filename: name)
}
}
What would be the most efficient way to convert a string like "ThisStringIsJoined" to "This String Is Joined" in objective-c?
I receive strings like this from a web service thats out of my control and I would like to present the data to the user, so I would just like to tidy it up a bit by adding spaces infront of each uppercase word. The strings are always formatted with each word beginning in an uppercase letter.
I'm quite new to objective-c so cant really figure this one out.
Thanks
One way of achieving this is as follows:
NSString *string = #"ThisStringIsJoined";
NSRegularExpression *regexp = [NSRegularExpression
regularExpressionWithPattern:#"([a-z])([A-Z])"
options:0
error:NULL];
NSString *newString = [regexp
stringByReplacingMatchesInString:string
options:0
range:NSMakeRange(0, string.length)
withTemplate:#"$1 $2"];
NSLog(#"Changed '%#' -> '%#'", string, newString);
The output in this case would be:
'ThisStringIsJoined' -> 'This String Is Joined'
You might want to tweak the regular expression to you own needs. You might want to make this into a category on NSString.
NSRegularExpressions are the way to go, but as trivia, NSCharacterSet can also be useful:
- (NSString *)splitString:(NSString *)inputString {
int index = 1;
NSMutableString* mutableInputString = [NSMutableString stringWithString:inputString];
while (index < mutableInputString.length) {
if ([[NSCharacterSet uppercaseLetterCharacterSet] characterIsMember:[mutableInputString characterAtIndex:index]]) {
[mutableInputString insertString:#" " atIndex:index];
index++;
}
index++;
}
return [NSString stringWithString:mutableInputString];
}
Here's a category on NSString that will do what you want. This will handle non-ASCII letters. It will also split "IDidAGoodThing" properly.
#implementation NSString (SeparateCapitalizedWords)
-(NSString*)stringBySeparatingCapitalizedWords
{
static NSRegularExpression * __regex ;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
NSError * error = nil ;
__regex = [ NSRegularExpression regularExpressionWithPattern:#"[\\p{Uppercase Letter}]" options:0 error:&error ] ;
if ( error ) { #throw error ; }
});
NSString * result = [ __regex stringByReplacingMatchesInString:self options:0 range:(NSRange){ 1, self.length - 1 } withTemplate:#" $0" ] ;
return result ;
}
#end
Here is Swift Code (objective c code by webstersx), Thanks !
var str: NSMutableString = "iLoveSwiftCode"
var str2: NSMutableString = NSMutableString()
for var i:NSInteger = 0 ; i < str.length ; i++ {
var ch:NSString = str.substringWithRange(NSMakeRange(i, 1))
if(ch .rangeOfCharacterFromSet(NSCharacterSet.uppercaseLetterCharacterSet()).location != NSNotFound) {
str2 .appendString(" ")
}
str2 .appendString(ch)
}
println("\(str2.capitalizedString)")
}
Output : I Love Swift Code
For anyone who came here looking for the similar question answered in Swift:
Perhaps a cleaner (adding to Sankalp's answer), and more 'Swifty' approach:
func addSpaces(to givenString: String) -> String{
var string = givenString
//indexOffset is needed because each time replaceSubrange is called, the resulting count is incremented by one (owing to the fact that a space is added to every capitalised letter)
var indexOffset = 0
for (index, character) in string.characters.enumerated(){
let stringCharacter = String(character)
//Evaluates to true if the character is a capital letter
if stringCharacter.lowercased() != stringCharacter{
guard index != 0 else { continue } //"ILoveSwift" should not turn into " I Love Swift"
let stringIndex = string.index(string.startIndex, offsetBy: index + indexOffset)
let endStringIndex = string.index(string.startIndex, offsetBy: index + 1 + indexOffset)
let range = stringIndex..<endStringIndex
indexOffset += 1
string.replaceSubrange(range, with: " \(stringCharacter)")
}
}
return string
}
You call the function like so:
var string = "iLoveSwiftCode"
addSpaces(to: string)
//Result: string = "i Love Swift Code"
Alternatively, if you prefer extensions:
extension String{
mutating func seperatedWithSpaces(){
//indexOffset is needed because each time replaceSubrange is called, the resulting count is incremented by one (owing to the fact that a space is added to every capitalised letter)
var indexOffset = 0
for (index, character) in characters.enumerated(){
let stringCharacter = String(character)
if stringCharacter.lowercased() != stringCharacter{
guard index != 0 else { continue } //"ILoveSwift" should not turn into " I Love Swift"
let stringIndex = self.index(self.startIndex, offsetBy: index + indexOffset)
let endStringIndex = self.index(self.startIndex, offsetBy: index + 1 + indexOffset)
let range = stringIndex..<endStringIndex
indexOffset += 1
self.replaceSubrange(range, with: " \(stringCharacter)")
}
}
}
}
Call the method from a string:
var string = "iLoveSwiftCode"
string.seperatedWithSpaces()
//Result: string = "i Love Swift Code"
You could try making a new string that is a lowercase copy of the original string. Then compare the two strings and insert spaces wherever the characters are different.
Use the NSString method to turn to lowercase.
- (NSString *)lowercaseString
How do you check if an NSString begins with a certain character (the character *).
The * is an indicator for the type of the cell, so I need the contents of this NSString without the *, but need to know if the * exists.
You can use the -hasPrefix: method of NSString:
Objective-C:
NSString* output = nil;
if([string hasPrefix:#"*"]) {
output = [string substringFromIndex:1];
}
Swift:
var output:String?
if string.hasPrefix("*") {
output = string.substringFromIndex(string.startIndex.advancedBy(1))
}
You can use:
NSString *newString;
if ( [[myString characterAtIndex:0] isEqualToString:#"*"] ) {
newString = [myString substringFromIndex:1];
}
hasPrefix works especially well.
for example if you were looking for a http url in a NSString, you would use componentsSeparatedByString to create an NSArray and the iterate the array using hasPrefix to find the elements that begin with http.
NSArray *allStringsArray =
[myStringThatHasHttpUrls componentsSeparatedByString:#" "]
for (id myArrayElement in allStringsArray) {
NSString *theString = [myArrayElement description];
if ([theString hasPrefix:#"http"]) {
NSLog(#"The URL is %#", [myArrayElement description]);
}
}
hasPrefix returns a Boolean value that indicates whether a given string matches the beginning characters of the receiver.
- (BOOL)hasPrefix:(NSString *)aString,
parameter aString is a string that you are looking for
Return Value is YES if aString matches the beginning characters of the receiver, otherwise NO. Returns NO if aString is empty.
As a more general answer, try using the hasPrefix method. For example, the code below checks to see if a string begins with 10, which is the error code used to identify a certain problem.
NSString* myString = #"10:Username taken";
if([myString hasPrefix:#"10"]) {
//display more elegant error message
}
Use characterAtIndex:. If the first character is an asterisk, use substringFromIndex: to get the string sans '*'.
NSString *stringWithoutAsterisk(NSString *string) {
NSRange asterisk = [string rangeOfString:#"*"];
return asterisk.location == 0 ? [string substringFromIndex:1] : string;
}
Another approach to do it..
May it help someone...
if ([[temp substringToIndex:4] isEqualToString:#"http"]) {
//starts with http
}
This might help? :)
http://developer.apple.com/mac/library/documentation/Cocoa/Reference/Foundation/Classes/NSString_Class/Reference/NSString.html#//apple_ref/occ/instm/NSString/characterAtIndex:
Just search for the character at index 0 and compare it against the value you're looking for!
This nice little bit of code I found by chance, and I have yet to see it suggested on Stack. It only works if the characters you want to remove or alter exist, which is convenient in many scenarios. If the character/s does not exist, it won't alter your NSString:
NSString = [yourString stringByReplacingOccurrencesOfString:#"YOUR CHARACTERS YOU WANT TO REMOVE" withString:#"CAN either be EMPTY or WITH TEXT REPLACEMENT"];
This is how I use it:
//declare what to look for
NSString * suffixTorRemove = #"</p>";
NSString * prefixToRemove = #"<p>";
NSString * randomCharacter = #"</strong>";
NSString * moreRandom = #"<strong>";
NSString * makeAndSign = #"&";
//I AM INSERTING A VALUE FROM A DATABASE AND HAVE ASSIGNED IT TO returnStr
returnStr = [returnStr stringByReplacingOccurrencesOfString:suffixTorRemove withString:#""];
returnStr = [returnStr stringByReplacingOccurrencesOfString:prefixToRemove withString:#""];
returnStr = [returnStr stringByReplacingOccurrencesOfString:randomCharacter withString:#""];
returnStr = [returnStr stringByReplacingOccurrencesOfString:moreRandom withString:#""];
returnStr = [returnStr stringByReplacingOccurrencesOfString:makeAndSign withString:#"&"];
//check the output
NSLog(#"returnStr IS NOW: %#", returnStr);
This one line is super easy to perform three actions in one:
Checks your string for the character/s you do not want
Can replaces them with whatever you like
Does not affect surrounding code
NSString* expectedString = nil;
if([givenString hasPrefix:#"*"])
{
expectedString = [givenString substringFromIndex:1];
}