What is an import statement where filename contains "+"? - objective-c

I have seen in some source code (by other developers) something like this:
#import "SomeClass+SomeOtherClass.h"
What is the + for? What does this mean?

Let's say you want to add functionality to an existing class (exp: NSString). You can do that by creating a subclass or you can use a category. And it is common to name the file where the category is defined using the pattern : MyClass+MyCategory.h.
For example, we can add a method reverseString to the class NSString in a category:
// File NSString+reversable.h
- (NSString *)reverseString;
// File NSString+reversable.m
- (NSString *)reverseString
{
// Implementation
}
Have a look at this documentation for more information about categories.
Then you can use that category in another class:
#import "NSString+reversable.h"
// ...
NSString *aString = #"Hello!";
NSString *reversedString = [aString reverseString];

The "+" in header/source filenames is - by convention - used to describe Category implementations.
Example :
Let's say you want to add some functionality to an existing class (e.g.the NSString class). (NSString+Utilities.h)
// NSString+Utilities.h
#interface NSString (Utilities)
-(NSString *) doSthWithThisString;
#end
// NSString+Utilities.m
#implementation NSString (Utilities)
-(NSString *) doSthWithThisString
{
NSMutableString *transformedStr = [self copy];
// Do sth
return transformedStr;
}
#end
Using it :
// in another file
#import "NSString+Utilities.h"
- (void)awakeFromNib
{
NSString* myString = #"This is a string";
// you may use our new NSString method as much as any already-existing one
NSString* newString = [myString doSthWithThisString];
}
Reference :
Mac OS Developer Library - Categories & Extensions
Objective-C Categories - Wiki

Related

Objective C - Category No Visible selector #removeWhiteSpaceStringWithString

so im trying to add new method for testing using Category from NSString, but some how i must declared like this with following step:
Create Category from NSString with name StringExtension so it will be NSString+StringExtension, after that i declared my own methos that return type is String
so after i define in NSString+StringExtension #interface and #implementation, i tried in my viewController to called it, but first i import the class NSString+StringExtension
after that i do like this
NSString *testString = #"as d a s d";
NSLog(#"===== %#", [testString removeWhiteSpaceStringWithString:testString]);
and it says
No visible #interface for 'NSString' declares the selector 'removeWhiteSpaceStringWithString:'
the question is, why it cannot use like that? i already search and see tutorial doing like that and its possible, but why i'm not able to do that?
so i found this way, but i don't know is this the correct code to use?
NSLog(#"===== %#", [[testString class] removeWhiteSpaceStringWithString:testString]);
anyone have the same case like i am?
Based upon what you have shared with us, it would appear that you defined a class method (with +). It should be an instance method (with -) and then you don’t need the parameter, either. You can simply reference self.
For example:
// NSString+Whitespace.h
#import Foundation;
NS_ASSUME_NONNULL_BEGIN
#interface NSString (Whitespace)
- (NSString *)stringByRemovingWhitespace;
#end
NS_ASSUME_NONNULL_END
And
// NSString+Whitespace.m
#import "NSString+Whitespace.h"
#implementation NSString (Whitespace)
- (NSString *)stringByRemovingWhitespace {
return [self stringByReplacingOccurrencesOfString:#"\\s+"
withString:#""
options:NSRegularExpressionSearch
range:NSMakeRange(0, self.length)];
}
#end
Then you can do:
NSString *testString = #"as d a s d";
NSLog(#"===== %#", [testString stringByRemovingWhitespace]); // ===== asdasd
Obviously, do whatever you want in your implementation, but it illustrates the idea, that you want an instance method and you do not need to pass the string again as a parameter.

Static NSLocalizedString

After checking a number of topics, I still can't figure something out : what is the (best?) way to use static NSLocalizedString, i.e. to statically allocate a NSLocalizedString and access it easily.
Ideally, I would want to do something like that (which won't compile, with an Initializer element is not a compile-time constant error):
//Somewhere in my header
static NSString* mystring = NSLocalizedString(#"min", nil); //Error : "Initializer element is not a compile-time constant"
#implementation myClass
(NSString*)aMethod
{
return myString;
}
#end
I know NSLocalizedString is a macro defined by #define NSLocalizedString(key, comment) \
[[NSBundle mainBundle] localizedStringForKey:(key) value:#"" table:nil], but that is not helping much :S.
Why ?
Long story short, to prevent the multiple definition of the same string in multiple parts of a document (which would prevent a one-stroke edit in my whole app).
Consider the example, where the redundancy of the definition is quiet explicit :
//MyDelegate.h
#property IBoutlet NSTextField* myTextField;
//MyDelegate.m
#implementation MyDelegate.m
#synthetize myTextField;
-(void)setTextFieldToDefaultValue
{
[myTextField setStringValue:NSLocalizedString(#"Name",#"This field is used to write one's name");
}
-(BOOL)isTextFieldStringDefault:(NSString*)myString
{
return [[myTextField stringValue] isEqual:NSLocalizedString(#"Name",#"This field is used to write one's name")];
}
#end
Of course, it makes more sense in a project which is quiet dense and big, where the string would be used in difference methods, and in a context where you have use of a lot of similar localized strings.
Generally this should all be in your implementation file:
static NSString* myString = nil;
#implementation myClass
+ (void)initialize
{
myString = NSLocalizedString(#"min", nil);
}
- (NSString *)aMethod
{
return myString;
}
#end
Well one more way you can write the same without using initialize method above:-
static NSString* mystring=nil;
-(NSString*)aMethod
{
mystring = NSLocalizedString(#"min", nil);
return mystring;
}

How to declare constants

I'm steadily getting the hang of Objective-C, but am still very much a beginner and have a beginner-level question hopefully someone could shed some light on:
If I have a very simple project and want to set a constant that I'll use throughout—say, a NSDictionary with keys being month names and values being days in that month—how is this done? (I.e., what command form and where to put it?)
NOTE: If this example is already possible using built-in functions, perhaps we could just pretend it isn't for the purposes of this question ;)
The answer depends on the type of your constant. If all you need is an int or a double, you can use preprocessor and the #define CONST 123 syntax. For Objective C classes, however, you need to do a lot more work.
Specifically, you would need to hide the constant behind a class method or a free-standing function. You will also need to add a prototype of that method or function in the header file, provide a function-scoped static variable to store the constant, and add code to initialize it.
Here is an example using a simple NSDictionary:
Header: MyConstants.h
#interface MyConstants
+(NSDictionary*)getConstDictionary;
#end
Implementation: MyConstants.m
+(NSDictionary*)getConstDictionary {
static NSDictionary *inst = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
inst = #{
#"key1": #"value1",
#"key2": #"value2",
#"key3": #"value3"
};
});
return inst;
}
Usage:
NSString *val = [[MyConstants getConstDictionary] objectForKey:#"key2"];
The accepted answer is correct, but if you prefer operate with variable (not trough method). I can suggest this pattern:
#implementation MyClass
static NSSet *mySetOfObjects;
+ (void)initialize {
mySetOfObjects = [[NSSet alloc] initWithObjects:#"one", #"two", #"three", nil];
}
// Example usage:
+ (BOOL)isRecognizedString:(NSString *)searchItem {
return [mySetOfObjects containsObject:searchItem];
}
#end
As for me - it looks better.
For more details the source is here.
Let's assume you want to declare an NSString constant in your class that holds a url. In your header .h file you will need the following:
#import
extern NSString * const BaseURL;
#interface ClassName : NSObject {
You will then need to set it's value in your main .m file as follows:
#import "ClassName.h"
NSString * const BaseURL = #"http://some.url.com/path/";
#implementation ClassName
You can now access this constant throughout your class or subclasses. Here's an example of usage:
NSString *urlString = [NSString stringWithFormat:#"%#%#", BaseURL, #"filename.html"];
If your constants are strings then you can use this form:
MyObject.h:
extern NSString *const kJanuary;
....
extern NSString *const kDecember;
#interface MyObject : NSObject
{
...
}
#end
MyObject.m:
NSString *const kJanuary = #"January";
....
NSString *const kDecember = #"December";
#implementation MyObject
....
#end
You can then use the constant kJanuary, for example, from anywhere when using your class.

Use NSString variable created in viewDidLoad inside another method

In my viewDidLoad method, I set the following variables:
// Get requested URL and set to variable currentURL
NSString *currentURL = self.URL.absoluteString;
//NSString *currentURL = mainWebView.request.URL.absoluteString;
NSLog(#"Current url:%#", currentURL);
//Get PDF file name
NSArray *urlArray = [currentURL componentsSeparatedByString:#"/"];
NSString *fullDocumentName = [urlArray lastObject];
NSLog(#"Full doc name:%#", fullDocumentName);
//Get PDF file name without ".pdf"
NSArray *docName = [fullDocumentName componentsSeparatedByString:#"."];
NSString *pdfName = [docName objectAtIndex:0];
I would like to be able to use these variables inside of another method (i.e. - (void)actionSheet:(UIActionSheet *)actionSheet clickedButtonAtIndex:(NSInteger)buttonIndex {)
How can I reuse these variables outside of the viewDidLoad method? I'm a newbie... help would be SO much appreciated
Make them an instance variable and not a variable local to the method you're using. After that, you can access them from all methods of the same class.
Example:
#interface MyClass: NSObject {
NSString *currentURL;
// etc.
}
- (void)viewDidLoad
{
currentURL = self.URL.absoluteString;
// etc. same from other methods
}
In terms of "global-variables" (as you tag says) within your class where you define the viewDidLoad create them as instance variables.
In your .h of the class
#interface MyViewController : UIViewController
{
NSArray *docName;
NSString *pdfName;
...
}
In your #interface (in the .h file) include this:
#property (nonatomic, strong) NSString *currentURL;
// the same for the rest of your variables.
Now you'll be able to access these properties by calling self.currentURL. If this is a newer project and ARC is turned on you don't have to bother with managing memory yourself.
Make them instance variable as H2CO3 suggests. Also you could just derive all your variables in the actionSheet:clickedButtonAtIndex function itself.
I notice that all the required variables are derived from self.URL.absoluteString. Therefore there should be no problem moving all your code, because self.URL is your instance variable that is holding what you want.
- (void)actionSheet:(UIActionSheet *)actionSheet clickedButtonAtIndex:(NSInteger)buttonIndex {
// Get requested URL and set to variable currentURL
NSString *currentURL = self.URL.absoluteString;
//NSString *currentURL = mainWebView.request.URL.absoluteString;
NSLog(#"Current url:%#", currentURL);
//Get PDF file name
NSArray *urlArray = [currentURL componentsSeparatedByString:#"/"];
NSString *fullDocumentName = [urlArray lastObject];
NSLog(#"Full doc name:%#", fullDocumentName);
//Get PDF file name without ".pdf"
NSArray *docName = [fullDocumentName componentsSeparatedByString:#"."];
NSString *pdfName = [docName objectAtIndex:0];
// Do what you need now...
}

Copy or retain NSString parameter?

I'm developing an iOs 4 app with latest SDK and XCode 4.2
I have a question about NSString parameters. This is my class definition:
#import <Foundation/Foundation.h>
#interface BlogEntry : NSObject
{
NSString* title;
NSString* text;
NSDate* date;
NSString* photo;
}
- (id)initWithTitle:(NSString*)titulo text:(NSString*)texto date:(NSDate*)fecha photo:(NSString*)foto;
#end
And implementation:
#import "BlogEntry.h"
#implementation BlogEntry
- (id)initWithTitle:(NSString*)titulo text:(NSString*)texto date:(NSDate*)fecha photo:(NSString*)foto
{
if (self = [super init])
{
title = titulo;
text = texto;
date = fecha;
photo = foto;
}
return self;
}
#end
May I need to retain initWithTitle parameters? Or, may I have to copy them?
If ARC, no. If non-ARC, yes.
For the NSString ivars, usually copy. For the NSDate ivar, retain. The reason for copy with NSString is in case an NSMutableString is passed in your init method. Copying the parameter prevents it from being mutated by your class. Thus, it ensures encapsulation.