I am trying to build Objective-C static frameworks but ran into hierarchy/organization problems.
For the question, assume I have 3 classes, classA, classB, and classC. classB and classC are children classes of classA. classB and classC each needs special resource files.
#import "classB.h"
#import "classC.h"
#implement classA
+ (classA)factoryMethodCreateType:(NSString *)type {
classA a;
if ([type isEqualToString:#"classB"]) {
a = [[classB alloc] init];
} else if ([type isEqualToString:#"classC"]) {
a = [classC alloc] init];
}
return a;
}
#end
I'd like to statically package the frameworks, classB.framework and classC.framework, such that when a user wants to use classB, they don't need to include classC and its resource files. Additionally, the user can use classA as the entry point to use either of the frameworks.
I assume if I just create classB.framework (includes classA and classB) and classC.framework (includes classA and classC), when the user wants to use both types and include both frameworks, the user will face duplicate symbols?
What is the best way to handle this situation? Is the following approach the best way to do it?
Change classA's implementation to dynamic creation of classB or classC and not include their header files.
Build 3 frameworks instead of 2: classA.framework, classB.framework, classC.framework. When the user wants to use classB, the the user should include both classA.framework and classB.framework.
#implement classA
+ (classA)factoryMethodCreateType:(NSString *)type {
classA a;
id obj = [NSClassFromString(type) alloc];
a = objc_msgSend(obj, #selector(init));
return a;
}
#end
main principles:
object could be created through class method by providing unique identifier (whatever)
if object with given identifier doesn't exists, returned new object otherwise returned existing one
class guarantees that ONLY ONE object with given identifier could exist (sort of internal singleton)
So main point in keeping objects with unique filed (f.e id) for future using, since they might have own states (f.e loading, loaded so on) we are allowed to use it everywhere we need it without re-creating.
Is it design pattern?
F.e:
Advirtisement.h
#interface Advertisment : NSObject
+ (instancetype)adWithID:(NSString *)adID;
+ (NSMutableArray *)sharedAds;
Advertisement.m
+ (instancetype)adWithID:(NSString *)adID {
NSMutableArray *ads = [[self class] sharedAds];
// Look for existing ad based on the id
Advertisement *returnableAd = nil;
for (Advertisement *currentAd in ads) {
if ([currentAd.adID isEqualToString:adID]) {
returnableAd = currentAd;
break;
}
}
// Create a new ad instance for this id if one doesn't already exist.
if (!returnableAd) {
returnableAd = [[[self class] alloc] initWithID:adID];
[ads addObject:returnableAd];
}
return returnableAd;
}
}
+ (NSMutableArray *)sharedAds
{
static NSMutableArray *sharedAds;
if (!sharedAds) {
sharedAds = [NSMutableArray array];
}
return sharedAds;
}
It's Lazy Initialization - and some would also consider it an instance of a Factory Pattern (others would argue that in itself a factory doesn't constitute a pattern)
If I want to access a variable that is declared in Class A and I
want to use that variable in Class B .
I don't want to use Property.
How Can I do ?
It is bad practice to declare a public variable without making it a property.
You may also use KVC to access(both read and write) ivar, even if it is readonly.
[instanceOfMyClass valueForKey:#"myIvar"];
I hope someone finds my first stackOverflow answer helpful :)
#interface Class1
{
#public
int var; // if you not declare it public by default it'll be protected
}
// methods...
#end
// Inside a Class2 method:
Class1 *obj = ...;
obj->var = 3;
But property approach is far better.
Well, you can declare variable as public and access it with selector operator, but this is not recommended:
#interface A:NSObject{
#public
int x;
}
#end
...
//Somewhere inside class B
A *a = [[A alloc] init];
a->x;
However it's hard to imagine why it can be better that to use a property.
The 4 possibles cases that I can think to access a variable are:
1 Declare the variable in class A as public
#public
BOOL _test;
Totally not recommended. If you need a public variable you use a property.
2 Use a property.
#property (readonly, getter = myMehtodName) id myVariable;
3 Use a custom method. In practice it acts the same as a property with readonly attribute. Also you can access it with the dot notation.
4 Use KVC to access the variable.
This can be useful when you don't know the name of the property / variable in compilation time.
A little example:
NSString *myKey = [self obtainKey];
id myVariable = [self valueForKey:myKey];
if ([myVariable isKindOfClass:[NSString class]]) {
//Do something
}else {
//Do another thing
}
Note that key can be either a method name or a variable.
I have a class in objective C which represents a generic business object ( let's say for my question sake its a bankaccount). I have a java C# background (FYI ). Now this bankAccount has an enum property defining what type it is, plus an NSURl property
//this is in the bankAccount.h file
typedef enum {Checking, Savings, Investor} AccountType;
-(NSURL *)url;
Now users can create a new bankaccount and set the enum to the relevant type. after allocating their new bankaccount object they might need to access the url property, so I have to implement a getter for that property which will initialize it properly. My question here is that how can I know what type of a bankaccount the calling class has created of my bankaccount in order to initialize the url property correctly?
like right now this is how I am implementing url in the bankaccount.m file :
-(NSURL *)url {
if (url != NULL) {
return url;
}
NSString *filePath;
// figure out the file path base on account type
switch (AccountType) {
}
return url;
}
keep in mind that this is in the Bankaccount.m file, which really doesn't know in the calling class what is the instance being created is. Maybe I am confused and maybe its a simple answer but I can't wrap my head around this concept.
Appreciate the help guys.
I think youre forgetting that you can't exactly save information in an enum. Save the value of the enum in some variable.
You do not necessarily have to setup your code like this, but maybe this is more what you are looking for.
// BankAccount.h
#import <Foundation/Foundation.h>
typedef enum {
Checking = 1,
Savings = 2,
Investor = 3
} AccountType;
#interface BankAccount : NSObject
-(void)setAccountType:(AccountType)theType; //Setter
-(NSURL *)url;
#end
// BankAccount.m
#import "BankAccount.h"
#implementation BankAccount
-(void)setAccountType:(AccountType)theType {
self.bankAccountType = theType;
}
-(NSURL *)url {
NSURL *someUrl;
switch (self.bankAccountType) {
case Checking:
someUrl = [NSURL URLWithString:#"http://xzyChecking"];
break;
case Savings:
someUrl = [NSURL URLWithString:#"http://xzySavings"];
break;
case Investor:
someUrl = [NSURL URLWithString:#"http://xzyInvestor"];
break;
default:
someUrl = [NSURL URLWithString:#"http://xzyError"];
break;
}
return someUrl;
}
#end
Is it possible to have blocks as properties using the standard property syntax?
Are there any changes for ARC?
#property (nonatomic, copy) void (^simpleBlock)(void);
#property (nonatomic, copy) BOOL (^blockWithParamter)(NSString *input);
If you are going to be repeating the same block in several places use a type def
typedef void(^MyCompletionBlock)(BOOL success, NSError *error);
#property (nonatomic) MyCompletionBlock completion;
Here's an example of how you would accomplish such a task:
#import <Foundation/Foundation.h>
typedef int (^IntBlock)();
#interface myobj : NSObject
{
IntBlock compare;
}
#property(readwrite, copy) IntBlock compare;
#end
#implementation myobj
#synthesize compare;
- (void)dealloc
{
// need to release the block since the property was declared copy. (for heap
// allocated blocks this prevents a potential leak, for compiler-optimized
// stack blocks it is a no-op)
// Note that for ARC, this is unnecessary, as with all properties, the memory management is handled for you.
[compare release];
[super dealloc];
}
#end
int main () {
#autoreleasepool {
myobj *ob = [[myobj alloc] init];
ob.compare = ^
{
return rand();
};
NSLog(#"%i", ob.compare());
// if not ARC
[ob release];
}
return 0;
}
Now, the only thing that would need to change if you needed to change the type of compare would be the typedef int (^IntBlock)(). If you need to pass two objects to it, change it to this: typedef int (^IntBlock)(id, id), and change your block to:
^ (id obj1, id obj2)
{
return rand();
};
EDIT March 12, 2012:
For ARC, there are no specific changes required, as ARC will manage the blocks for you as long as they are defined as copy. You do not need to set the property to nil in your destructor, either.
For more reading, please check out this document:
http://clang.llvm.org/docs/AutomaticReferenceCounting.html
#property (copy)void
#property (copy)void (^doStuff)(void);
The actual Apple documentation which states precisely what to use:
Apple doco.
Your .h file:
// Here is a block as a property:
//
// Someone passes you a block. You "hold on to it",
// while you do other stuff. Later, you use the block.
//
// The property 'doStuff' will hold the incoming block.
#property (copy)void (^doStuff)(void);
// Here's a method in your class.
// When someone CALLS this method, they PASS IN a block of code,
// which they want to be performed after the method is finished.
-(void)doSomethingAndThenDoThis:(void(^)(void))pleaseDoMeLater;
// We will hold on to that block of code in "doStuff".
Your .m file:
-(void)doSomethingAndThenDoThis:(void(^)(void))pleaseDoMeLater
{
// Regarding the incoming block of code, save it for later:
self.doStuff = pleaseDoMeLater;
// Now do other processing, which could follow various paths,
// involve delays, and so on. Then after everything:
[self _alldone];
}
-(void)_alldone
{
NSLog(#"Processing finished, running the completion block.");
// Here's how to run the block:
if ( self.doStuff != nil )
self.doStuff();
}
Beware of out-of-date example code.
With modern (2014+) systems this is the correct and documented approach.
For posterity / completeness's sake… Here are two FULL examples of how to implement this ridiculously versatile "way of doing things". #Robert's answer is blissfully concise and correct, but here I want to also show ways to actually "define" the blocks.
#interface ReusableClass : NSObject
#property (nonatomic,copy) CALayer*(^layerFromArray)(NSArray*);
#end
#implementation ResusableClass
static NSString const * privateScope = #"Touch my monkey.";
- (CALayer*(^)(NSArray*)) layerFromArray {
return ^CALayer*(NSArray* array){
CALayer *returnLayer = CALayer.layer
for (id thing in array) {
[returnLayer doSomethingCrazy];
[returnLayer setValue:privateScope
forKey:#"anticsAndShenanigans"];
}
return list;
};
}
#end
Silly? Yes. Useful? Hells yeah. Here is a different, "more atomic" way of setting the property.. and a class that is ridiculously useful…
#interface CALayoutDelegator : NSObject
#property (nonatomic,strong) void(^layoutBlock)(CALayer*);
#end
#implementation CALayoutDelegator
- (id) init {
return self = super.init ?
[self setLayoutBlock: ^(CALayer*layer){
for (CALayer* sub in layer.sublayers)
[sub someDefaultLayoutRoutine];
}], self : nil;
}
- (void) layoutSublayersOfLayer:(CALayer*)layer {
self.layoutBlock ? self.layoutBlock(layer) : nil;
}
#end
This illustrates setting the block property via the accessor (albeit inside init, a debatably dicey practice..) vs the first example's "nonatomic" "getter" mechanism. In either case… the "hardcoded" implementations can always be overwritten, per instance.. a lá..
CALayoutDelegator *littleHelper = CALayoutDelegator.new;
littleHelper.layoutBlock = ^(CALayer*layer){
[layer.sublayers do:^(id sub){ [sub somethingElseEntirely]; }];
};
someLayer.layoutManager = littleHelper;
Also.. if you want to add a block property in a category... say you want to use a Block instead of some old-school target / action "action"... You can just use associated values to, well.. associate the blocks.
typedef void(^NSControlActionBlock)(NSControl*);
#interface NSControl (ActionBlocks)
#property (copy) NSControlActionBlock actionBlock; #end
#implementation NSControl (ActionBlocks)
- (NSControlActionBlock) actionBlock {
// use the "getter" method's selector to store/retrieve the block!
return objc_getAssociatedObject(self, _cmd);
}
- (void) setActionBlock:(NSControlActionBlock)ab {
objc_setAssociatedObject( // save (copy) the block associatively, as categories can't synthesize Ivars.
self, #selector(actionBlock),ab ,OBJC_ASSOCIATION_COPY);
self.target = self; // set self as target (where you call the block)
self.action = #selector(doItYourself); // this is where it's called.
}
- (void) doItYourself {
if (self.actionBlock && self.target == self) self.actionBlock(self);
}
#end
Now, when you make a button, you don't have to set up some IBAction drama.. Just associate the work to be done at creation...
_button.actionBlock = ^(NSControl*thisButton){
[doc open]; [thisButton setEnabled:NO];
};
This pattern can be applied OVER and OVER to Cocoa API's. Use properties to bring the relevant parts of your code closer together, eliminate convoluted delegation paradigms, and leverage the power of objects beyond that of just acting as dumb "containers".
Of course you could use blocks as properties. But make sure they are declared as #property(copy). For example:
typedef void(^TestBlock)(void);
#interface SecondViewController : UIViewController
#property (nonatomic, copy) TestBlock block;
#end
In MRC, blocks capturing context variables are allocated in stack; they will be released when the stack frame is destroyed. If they are copied, a new block will be allocated in heap, which can be executed later on after the stack frame is poped.
Disclamer
This is not intended to be "the good answer", as this question ask explicitly for ObjectiveC. As Apple introduced Swift at the WWDC14, I'd like to share the different ways to use block (or closures) in Swift.
Hello, Swift
You have many ways offered to pass a block equivalent to function in Swift.
I found three.
To understand this I suggest you to test in playground this little piece of code.
func test(function:String -> String) -> String
{
return function("test")
}
func funcStyle(s:String) -> String
{
return "FUNC__" + s + "__FUNC"
}
let resultFunc = test(funcStyle)
let blockStyle:(String) -> String = {s in return "BLOCK__" + s + "__BLOCK"}
let resultBlock = test(blockStyle)
let resultAnon = test({(s:String) -> String in return "ANON_" + s + "__ANON" })
println(resultFunc)
println(resultBlock)
println(resultAnon)
Swift, optimized for closures
As Swift is optimized for asynchronous development, Apple worked more on closures.
The first is that function signature can be inferred so you don't have to rewrite it.
Access params by numbers
let resultShortAnon = test({return "ANON_" + $0 + "__ANON" })
Params inference with naming
let resultShortAnon2 = test({myParam in return "ANON_" + myParam + "__ANON" })
Trailing Closure
This special case works only if the block is the last argument, it's called trailing closure
Here is an example (merged with inferred signature to show Swift power)
let resultTrailingClosure = test { return "TRAILCLOS_" + $0 + "__TRAILCLOS" }
Finally:
Using all this power what I'd do is mixing trailing closure and type inference (with naming for readability)
PFFacebookUtils.logInWithPermissions(permissions) {
user, error in
if (!user) {
println("Uh oh. The user cancelled the Facebook login.")
} else if (user.isNew) {
println("User signed up and logged in through Facebook!")
} else {
println("User logged in through Facebook!")
}
}
Hello, Swift
Complementing what #Francescu answered.
Adding extra parameters:
func test(function:String -> String, param1:String, param2:String) -> String
{
return function("test"+param1 + param2)
}
func funcStyle(s:String) -> String
{
return "FUNC__" + s + "__FUNC"
}
let resultFunc = test(funcStyle, "parameter 1", "parameter 2")
let blockStyle:(String) -> String = {s in return "BLOCK__" + s + "__BLOCK"}
let resultBlock = test(blockStyle, "parameter 1", "parameter 2")
let resultAnon = test({(s:String) -> String in return "ANON_" + s + "__ANON" }, "parameter 1", "parameter 2")
println(resultFunc)
println(resultBlock)
println(resultAnon)
You can follow the format below and can use the testingObjectiveCBlock property in the class.
typedef void (^testingObjectiveCBlock)(NSString *errorMsg);
#interface MyClass : NSObject
#property (nonatomic, strong) testingObjectiveCBlock testingObjectiveCBlock;
#end
For more info have a look here