Which of the following will be efficient or faster in iOS? - objective-c

Which of the following will be efficient or faster in iOS?
/* Public Static Variable */
static UICollectionView *mDocsCollection;
#interface ClassA ()
{
}
#end
#implementation ClassA
- (UICollectionView *)documentsCollection
{
if (!mDocsCollection) {
mDocsCollection = (UICollectionView *)[self.view viewWithTag:VIEW_TAG_DOCS_COLLECTION];
}
return mDocsCollection;
}
#end
/* Interface Variable */
#interface ClassA ()
{
UICollectionView *mDocsCollection;
}
#end
#implementation ClassA
- (UICollectionView *)documentsCollection
{
if (!mDocsCollection) {
mDocsCollection = (UICollectionView *)[self.view viewWithTag:VIEW_TAG_DOCS_COLLECTION];
}
return mDocsCollection;
}
#end
/* Private Static Variable */
- (UICollectionView *)documentsCollection
{
static UICollectionView *docsCollection;
if (!docsCollection) {
docsCollection = (UICollectionView *)[self.view viewWithTag:VIEW_TAG_DOCS_COLLECTION];
}
return docsCollection;
}
/* Typecasting is done every time (No Variables used) */
- (UICollectionView *)documentsCollection
{
return (UICollectionView *)[self.view viewWithTag:VIEW_TAG_DOCS_COLLECTION];
}

With the speed of todays devices I doubt there would be any measurable difference. However there are some other observations:
As per other comments, it's not a good idea to use static variables in these situations. In fact, I recommend only using statics where absolutely necessary.
Again unless necessary, I recommend to people to avoid using viewWithTag:. It may seem like an easy solution to finding controls at first. But once you project becomes larger or other programmers join, it's a likely cause of on going bugs. I recommend using IBOutlets and/or UIView extends so that you have direct access to correctly typed references to the controls that always point to the control you want.
And by using an IBOutlet or property, you simply would not need any of these methods :)

The last is slowest. The others are equally fast, probably only a few machine instructions apart.
The file-scope static and the method-scope static do the same thing. The ivar does something very different. This matters if you have multiple instances of ClassA or multiple threads, in which case the statics are probably simply wrong.

I doubt the difference will be observable in this case, but you could benchmark it and see. A simple-minded benchmark would do something like:
CFAbsoluteTime startTime = CFAbsoluteTimeGetCurrent();
// put the code to benchmark here
NSLog(#"elapsed = %f seconds", CFAbsoluteTimeGetCurrent() - startTime);
You might want to repeat your tests many times so you establish a confidence level on the numbers you generate. Also note that the order in which you test them can affect the results, so you might want to delay the benchmarking code until the app has really finished loading and quieted down.
Theoretically, if you call this documentsCollection method a lot, storing the value in a variable might offer some performance improvement, but you'd only bother with this sort of implementation when using some very expensive method or if you're calling it a lot.
FYI, the static implementations can result in very different behavior if its possible that you might reinstantiate ClassA more than once (i.e. dismiss the view controller and re-present it later). The static variables are not unique to just this instance of ClassA, but are shared across instances. Given that you're dealing with views, I doubt this behavior is desirable.

Related

In Objective-C is there a way to get a list of the methods called by a method?

I have been doing some research online and have found that using the ObjectiveC package in Objective C you can get a list of all the methods on a class using class_copyMethodList(), and I see you can get the implementation (IMP) of a method using instanceMethodForSelector:. The Apple documentation here has been helpful so far but I'm stuck and not sure what I'm really looking to find.
I want a list of the methods/functions called in a given method's implementation so I can build a call tree.
Any suggestions? Thanks in advance!
This solution is kind of hard way, and will cause a line of code in every method You can also make use of sqlite and save the tracked methods..
MethodTracker.h
#interface MethodTracker : NSObject
#property (nonatomic) NSMutableArray *methodTrackArr;
+ (MethodTracker *)sharedVariables;
#end
MethodTracker.m
#implementation MethodTracker
static id _instance = nil;
+ (MethodTracker *)sharedVariables
{
if (!_instance)
_instance = [[super allocWithZone:nil] init];
return _instance;
}
// optional
- (void)addMethod:(NSString *)stringedMethod
{
// or maybe filter by: -containObject to avoid reoccurance
[self.methodTrackArr addObject:stringedMethod];
NSLog("current called methods: %#", methodTrackArr);
}
#end
and using it like:
OtherClass.m
- (void)voidDidLoad
{
[super viewDidLoad];
[[MethodTracker sharedVariables] addMethod:[NSString stringWithUTF8String:__FUNCTION__]];
// or directly
[[MethodTracker sharedVariables].methodTrackArr addObject:[NSString stringWithUTF8String:__FUNCTION__]];
}
- (void)someOtherMethod
{
// and you need to add this in every method you have (-_-)..
[[MethodTracker sharedVariables] addMethod:[NSString stringWithUTF8String:__FUNCTION__]];
}
i suggest you import that MethodTracker.h inside [ProjectName]-Prefix.pch file.
Sorry, for the double answer, i deleted the other one and i have no idea how did that happen..
Hope this have helped you or at least gave you an idea.. Happy coding,
Cheers!
I think in the runtime track method is possible, but function not.
I have been build a tool DaiMethodTracing for trace all methods activity in single class for some of my need. This is based on objective-c method swizzling. So, there is an idea to do this
List all Classes in your application.
swizze all the methods in each class.
filter the method you want to trace.
finally, you may got the method call path.

What is the recommended method of styling an iOS app?

What is the recommended method of styling an iOS app? For example, if there are multiple labels or text views how can updating font style/color at one place update the style/color at all other places?
I know sub classing could be one way... is there any other way?
You could import a standard header file into all your controllers with several constants set for styling... example:
Styles.h
#define kFontSize 14
#define kFontFamily #"Helevetica"
Controller
#import "Styles.h" // at the top
myLabel.font = [UIFont fontWithName:kFontFamily size:kFontSize];
I personally think Interface Builder is the best way to style, however this answers your question directly.
Update: I would recommend starting by understanding UIAppearance APIs, and seeing how well they suit your needs. UIAppearance is a convenient way to provide custom default stylization of specific controls' attributes at multiple levels (e.g. globally or contextually).
My original answer, which predated UIAppearance's availability:
since we're working with an object based language...
for the implementation, it depends on how you want it to behave/execute. when the implementation becomes nontrivial, i will often create a protocol. you could use class methods or instance methods and significantly optimize these types for your usage because you create fewer intermediate colors, fonts, images, etc.
a basic interface could take the form:
#protocol MONLabelThemeProtocol
- (UIFont *)labelFont;
- (UIColor *)labelTextColor;
- (UITextAlignment)labelTextAlignment;
// ...
#end
#protocol MONTableViewCellThemeProtocol
- (UIFont *)tableViewCellFont;
- (UIColor *)tableViewCellTextColor;
- (UIImage *)tableViewCellImage;
- (NSInteger)tableViewCellIndentationLevel;
- (CGFloat)tableViewCellIndentationWidth;
// ...
#end
then a simple amalgamate theme could be declared like this:
#interface MONAmalgamateThemeBase : NSObject
< MONLabelThemeProtocol, MONTableViewCellThemeProtocol >
{
#protected
/* labels */
UIFont * labelFont;
UIColor * labelTextColor;
UITextAlignment labelTextAlignment;
// ...
/* table view cells */
UIFont * tableViewCellFont;
UIColor * tableViewCellTextColor;
UIImage * tableViewCellImage;
NSInteger tableViewCellIndentationLevel;
CGWidth tableViewCellIndentationWidth;
// ...
}
#end
in this example, the amalgamate defines the getters and dealloc and expects the subclasses to initialize the instance variables. you could also support lazy initialization if initialization times are high (e.g. uses many images).
then a specialization could take the form:
#interface MONDarkTheme : MONAmalgamateThemeBase
#end
#implementation MONDarkTheme
- (id)init
{
self = [super init];
if (nil != self) {
labelFont = [[UIFont boldSystemFontOfSize:15] retain];
labelTextColor = [[UIColor redColor] retain];
// and so on...
}
return self;
}
// ...
#end
/* declare another theme and set it up appropriately */
#interface MONLightTheme : MONAmalgamateThemeBase
#end
then just reuse the theme instances (e.g. MONDarkTheme) throughout the app to stylize the views. if you have a lot of themes or they are not trivial to construct, then you may want to create a collection for themes (theme manager). the amalgamate could also take a parameter, such as init with theme if your needs are simple. you can even configure objects to register for changes to themes, if you need support for dynamic changes.
finally, you can create a simple theme applier to make life easier - like so:
#interface UILabel (MONThemeAdditions)
- (void)mon_applyMONLabelTheme:(id<MONLabelTheme>)theme;
#end
#implementation UILabel (MONThemeAdditions)
- (void)mon_applyMONLabelTheme:(id<MONLabelTheme>)theme
{
assert(theme);
if (nil == theme) return;
self.font = [theme labelFont];
self.textColor = [theme labelTextColor];
self.textAlignment = [theme labelTextAlignment];
}
#end
Frankly, the best way to go about this is to use Interface Builder. While it might seem nice to change a single constant somewhere in the code and have the entire app change styles, it never quite works out that way. Here are my reasonings:
1) Developers don't write interface code as well as interface builder does.
Interface builder is a tool that has been refined, tested, and intreated over years. It offers fonts, text alignment, shadow, etc. It is backwards compatible for as far back as you'd ever want. It provides a very simple way for any number of developers and designers to jump in and work on something very straightforward.
2) There are always edge cases that you'll have to account for. Sure, a simple constant will do what you want most the time, but you'll eventually have to hack something in here and sneak something in there. The "simple" interface code you wrote to start off will grow and grow and grow. Other developers will have to maintain that code. You will have to maintain that code. You will have to file and fix bugs, tweak this, except that, etc. It will inevitably become a steaming pile of mess.
3) The more code you write, the more bugs you write. Interface builder is for building the 'look' of most iOS apps. Use it. Don't get too clever.
NOTE:
I understand that Interface builder cannot do everything for all apps. There are cases that coding an interface is the only solution. This answer is simply a general "best practice" I use in the bulk of my apps.
Similar to Alex's idea, you could create a static class called ThemeManager:
typedef enum
{
defaultStyle,
redStyle,
} ThemeStyles;
#interface Level : NSObject
{
ThemeStyles currentTheme;
}
All classes which can be themed will import ThemeManager. Then, you can create methods like:
+ (UIColor*) fontColor;
Which other classes would call when they want a color for their font. Then, if you want to change themes, you could implement fontColor as:
+ (UIColor*) fontColor
{
switch (currentTheme)
{
case defaultStyle:
return [UIColor blackColor];
case redStyle:
return [UIColor redColor];
}
}
When you want to change the theme, you could have ThemeManager implement a method like:
+ (void) changeTheme:(ThemeStyles)newTheme
{
currentTheme = newTheme;
}
You can use a third-party abstraction of UIAppearance:
NUI: https://github.com/tombenner/nui
Pixate: http://www.pixate.com
Using a Storyboard has a lot of benefits, but many style options aren't available, not the least of which is custom fonts. If you want a deeply-customized UI, you will need some style code to make it happen.
I use plists. Just as I localize strings, I use the same procedure to change themes. I coded a singleton that loads a current theme plist and a fallback plist. Then I replace the names of resources with keys and macro functions that pull the real resource name from the singleton.
Cons: you have to set the resource for each element, not just set it in the NIB.
Pros: once you are done, most of the next theme involves photoshop and textmate, not IB or code.
You may need to look at this library. It supports multiple themes/skins on the fly. Supports images and colors currently. Font support will be added in future.
https://github.com/charithnidarsha/MultiThemeManager

Should I include the managed object context as a parameter to a method?

Problem
I'm including the managed object context as a parameter of a method when I work with Core Data.
Although this makes the code easier to test, it's messy.
Questions
Is this good or bad practice?
Is there a neater, easier way of doing this that keeps methods testable?
Background
The example below is a background operation that has it's own context.
Any advice from more experienced coders would be much appreciated!
Code
#interface JGTrainingGroupCleanupOperation : JGCoreDataOperation {
NSManagedObjectContext *imoc;
}
...
#implementation JGTrainingGroupCleanupOperation
-(void)main {
[self startOperation]; // Setting up the local context etc
[self cleanupTrainingGroupsInMOC:imoc];
[self finishOperation];
}
-(void)cleanupTrainingGroupsInMOC:(NSManagedObjectContext *)moc {
NSSet *trainedGroups = [self fetchAllTrainedGroupsInMOC:moc];
[self deleteDescendantsOfGroups:trainedGroups fromMOC:moc];
[self removeStubAncestorsOfGroups:trainedGroups fromMOC:moc];
}
-(NSSet *)fetchAllTrainedGroupsInMOC:(NSManagedObjectContext *)moc_ {
return [moc_ fetchObjectsForEntityName:kTrainingGroup withPredicate:[NSPredicate predicateWithFormat:#"projectEditedAtTopLevel == nil"]];
}
-(void)deleteDescendantsOfGroups:(NSSet *)trainedGroups fromMOC:(NSManagedObjectContext *)moc_ {
// More code here
}
-(void)deleteDescendantsOfGroup:(JGTrainingGroup *)trainedGroup fromMOC:(NSManagedObjectContext *)moc_ {
// More code here
}
In my (not so humble) opinion I'd say it's mostly a matter of style. You can do it this way or you can #synthesize the moc and call [self moc] or self.moc.
Me? I'd go the accessor route personally, mostly because class members shouldn't have to be told where to find an object dereferenced by an iVar anyway. If you're accessing something that's an iVar within the same class, I'd use the iVar directly or an accessor.
I believe the difference in performance would be negligible, so I wouldn't really bother much on that front (even though you didn't ask).

Pull-up refactoring, Objective-C

I have two similar classes, MultiSlotBlock and SingleSlotBlock. They have started to share a lot of common code so I have decided to do some refactoring and pull some of the methods up to a new superclass, let's call it Block.
Now one of the methods that I pull up, simplified for the example, looks like this:
// (Block.mm)
- (void)doACommonBehaviour
{
// .. does some stuff
[self doAUniqueBehaviour];
}
The problem here is that [self doAUniqueBehaviour] is showing a warning because of course my superclass doesn't implement this method anywhere.
The two solutions I thought of don't sound great to me. One is to use a protocol (the way I am currently doing it) like so:
// (Block.mm)
- (void)doACommonBehaviour
{
// .. does some stuff
if ([self conformsToProtocol:#protocol(UniqueBehaviourProtocol)])
{
id<UniqueBehaviourProtocol> block = (id<UniqueBehaviourProtocol>)self;
[block doAUniqueBehaviour];
}
}
The other is to have a blank method body in my superclass (in this case there would be a lot) and just return doesNotRespondToSelector.
Something is tingling at the back of my mind that I should be using the Strategy Pattern, but I might be way off, and I haven't thought through how that would be implemented.
Any ideas? Thanks.
EDIT: I know for a fact that doAUniqueBehaviour will be implemented in all subclasses, it is just the implementation that will differ.
The superclass should not know about its subclasses. You should implement the
- (void)doACommonBehaviour method in every subclass and there:
- (void)doACommonBehaviour
{
[super doACommonBehaviour];
[self doAUniqueBehaviour];
}
EDIT - clarification:
If all the subclasses are going to implement -doAUniqueBehaviour then it should be implemented in the superclass (even empty) and each subclass will override it to its needs.
If subclass1 implements -doAUniqueBehaviour1, subclass2 implements -doAUniqueBehaviour2 etc then do what I propose above; eg. in subclass1:
- (void)doACommonBehaviour
{
[super doACommonBehaviour];
[self doAUniqueBehaviour1];
}
There is not such concept as abstract class in Objective-C. In order to avoid the warning, you have to provide a default implementation in your base class. Usually, this implementation will throw a doesNotRespondToSelector error at runtime:
- (id)someMethod:(SomeObject*)blah
[self doesNotRecognizeSelector:_cmd];
return nil;
}
Note: the _cmd argument is the invoked selector.
#Dimitri's suggestion will work, but instead of forcing each subclass to implement the same method, you can declare it once in Block, and just above that method (in the implementation file, not header) declare the unique method like so:
- (void) doUniqueBehaviour { }
- (void) doCommonBehaviour {
// any common code you need
[self doUniqueBehaviour];
}
This will prevent any compiler warnings, and you can override -doUniqueBehaviour in subclasses as you like. It also avoids code duplication and reduces the potential for changing the code in one subclass but not another. Plus, you don't need a separate protocol, and dynamic typing is preserved.

Count the number of times a method is called in Cocoa-Touch?

I have a small app that uses cocos2d to run through four "levels" of a game in which each level is exactly the same thing. After the fourth level is run, I want to display an end game scene. The only way I have been able to handle this is by making four methods, one for each level. Gross.
I have run into this situation several times using both cocos2d and only the basic Cocoa framework. So is it possible for me to count how many times a method is called?
Can you just increment an instance variable integer every time your method is called?
I couldn't format the code in a comment, so to expound more:
In your header file, add an integer as a instance variable:
#interface MyObject : NSObject {
UIInteger myCounter;
}
And then in your method, increment it:
#implementation MyObject
- (void)myMethod {
myCounter++;
//Do other method stuff here
if (myCounter>3){
[self showEndGameScene];
}
}
#end
I don't know if your way is the best way to do it, or if mine is, but like Nathaniel said, you would simply define an integer to hold the count in your #interface:
#interface MyClass : NSObject {
int callCount;
}
Then the method can increment this by doing:
- (void) theLevelMethod {
callCount++;
// some code
}
Make sure you initialize the callCount variable to 0 though, in your constructor or the equivalent of viewDidLoad. Then in the code that checks the count you can check:
if (callCount == 4) {
// do something, I guess end scene
}
Then again, I guess you can simply do something like this:
for (int i = 0; i < 4; i++) {
[self theLevelMethod];
}
[self theEndScene];
I don't know how your game logic works, but I guess that would work.
Sorry if I misunderstood your question.