I realize that what counts as premature optimization has a subjective component, but this is an empirical or best-practices question.
When programming for iOS, should I prefer using struct and typedefs where the object has no "behavior" (methods, basically)? My feeling is that the struct syntax is a bit strange for a non-C person, but that it should be WAY lower profile. Then again, testing some cases with 50K NSObject instances, it doesn't seem bad (relative, I know). Should I "get used to it" (use structs where possible) or are NSObject instances okay, unless I have performance problems?
The typical case would be a class with two int member variables. I've read that using a struct to hold two NSString instances (or any NSObject subclass) is a bad idea.
Structs with NSObject instances in them are definitely a bad idea. You need -init and -dealloc to handle the retain count correctly. Writing retain and releases from the caller side is just insane. It will never pay off.
Structs with two int or four doubles are borderline cases. The Cocoa framework itself implements NSRect, NSPoint etc. as a struct. But that fact has confused lots and lots of newcomers. Honestly, even the distinction between primitive types and object types confused them. It becomes even confusing to me when you have structs as properties of an object: you can't do
object.frame.origin.x=10;
If you start making your own structs, you need to remember which is which. That's again a hassle. I think the reason why they (NSRect etc.) are structs are basically historical.
I would prefer to make everything objects. And use garbage collection if available.
And, don't ask people if something is worth optimizing or not. Measure it yourself by Instruments or whatever. Depending on the environment (ppc vs intel, OS X vs iOS, iPad vs iPhone) one way which was faster in a previous system might be slower in a new system.
An Objective C object has almost the same storage as a struct, except it is 4 bytes (8 bytes on 64 bit) bigger. That's it - just one pointer into a place where the runtime holds all the class information.
If you are that tight on memory, then lose the 4 bytes, but usually that's only for large numbers of objects: 50,000 Nsobjects vs structs is only 200k - you get a lot of stuff for that 200k. For a million objects, the cost will add up on an iPhone.
If you want to say transfer the items to openGL or need a c array for other purposes, then another option is to make ONE NSObject that has a malloc'ed pointer to all 50,000 integers. Then the objective c memory overhead is ~0, and you can encapsulate all the nasty malloc and free() stuff into the innards of one .m file.
Go with regular objects until you hit a measurable performance bottleneck. I’ve used high-level code even in tight game loops without problems – messaging, collection classes, autorelease pools, no problems.
I see no problem at all with using structs to hold small quantities of primitive (i.e. non object) types where there is no behaviour required. There are already several examples of this in the Cocoa frameworks (CGRect, CGSize, CGPoint, NSRange for example).
Do not use structs to hold Objective-C objects. It complicates the memory management in the reference counted environment and may break it altogether in the GC environment.
For me, I would prefer to use regular objects because you can easily do Object job with it like retain, release, autorelease. I only see quite few structs in Cocoa Framework like CGSize, CGRect and CGPoint. I think the reason is that they are being used a lot
I believe is a good idea to use structs specially if you are dealing with C-based frameworks , lets says OpenGL, CoreGraphics, CoreText specially stuff that will require a couple/triple of ints, doubles, chars, etc. (If they are already not implemented in some of Apple Frameworks: CGRect, CGPoint, CTRect, NSRange, etc...) C stuff plays and looks better with other C stuff.
I don't think I would write a subclass of NSObject containing a couple of ints. It's almost ridiculous. lol.
Related
In comparing these two options for defining an instance property:
var networkManager = NetworkManager.sharedInstance()
var lazy networkManager = NetworkManager.sharedInstance()
Both:
Can evaluate a block to get the value
Can be declared inline (not a block, like above)
Lazy:
Can refer to self
Is not calculated until needed
If you don't use it, it is never calculated
Non-lazy:
No benefits whatsoever
It appears that there is no benefit to ever use a non-lazy variable. So why does the language allow the programmer to make this inferior choice?
(I am NOT asking about the difference between var and let à la Are Swift constants lazy by default?)
One reason might be that lazyness is not well-suited for situations where you want control when the evaluation happens. this is relevant in cases where the work being done in the assignment has side effects.
Although this pertains to closure, this blog post by stuart sierra explains this idea very well, and I think it applies equally in any language.
As others already said, there are several critical scenarios where you want the initialization of the properties to be deterministic.
This is an example (among many others) related to game development.
Often the instances of classes representing items in a game scene/level, are created before the level does begin.
Initialisation can be a time expensive task (load stuff from persistent storage, allocate memory, prepare the instances...) and doing this part before the player does begin playing the level does avoid CPU overhead.
This is critical because a CPU overhead in the middle of a level could cause a drop in the frame rate which is a nightmare for the user experience.
FYI. My feeling is that Swift wants to become more like a functional language and would like lazy instantiation in more places.
My early assessment of Swift has held up pretty well over time (well, the "not functional" part. I didn't anticipate how much Swift would favor methods over functions in later versions). Swift is not a functional language and does not intend to be one. This has come up often in WWDC talks, on the forums, on Twitter, and in conversations with the Swift team. Originally all maps and filters were lazy. Swift removed that because of the problems it caused. Probably the best talk on that subject is "Building Better Apps with Value Types in Swift". As they say:
We like mutation. We think it's valuable. We think it's easy to use when done correctly.
You don't get much more "non-functional" than that. Swift also embraces immutable data. But functional programming is about pure functions over immutable data, and that's not Swift.
(Of course there are plenty of non-lazy functional languages. Lazy and functional are orthogonal concepts. Haskell just happened to embrace both.)
To the question at hand, though:
I've found the lazy attribute rarely useful in real-world Swift (I'm being generous; I have never encountered a case where I kept it in the code). It doesn't offer anything like the laziness you get in Haskell. It isn't thread safe, so that's a nightmare. It forces you into reference types (or forces your structs to be mutable), so that can be annoying. If I heard they were pulling it from the language and we just had to roll our own, that'd be fine with me. (I'm tempted to write a proposal to do just that.) It implements a specific memo pattern that can occasionally be handy, but often isn't the one you want. So it's a very good thing that it isn't the default.
As you likely know, global variables and class variables are lazy by default, and I think that tends to work out pretty well since there are so many fewer of them, there's a much better chance they won't be accessed in practice, and that laziness is thread safe (which has a cost, but since they're so much rarer, the cost is much lower).
If you have an expensive object (in terms of, takes long to create) you would like to decide and control when it is created. One could argue that the lazy variable should be the default though. Maybe it has historical reasons. Lazy properties in ObjC resulted in a lot boilerplate code.
I'm trying to memory test my app.
I've followed the Organizer - Documentation article entitled "Recovering Memory You Have Abandoned", but I'm not sure if the results make my tested page good or bad, or somewhere in-between.
(My test involved: navigate to page 2, going back to page 1, press 'Mark Heap' -repeated 25 times for good measure.)
Attached is a screenshot of my allocations test. Most of the #Persistent values are 0. But there are some anomalies. Are these typical?
(The last Heapshot, 26, was taken after stopping the recording, and pressing 'Mark Heap' at the end of the trace - as suggested in the documentation.)
I would be very grateful for some advice. Thanks.
I believe that you are using ARC, and if you are using ARC, there is no need of bothering about the heaps, it will take care of everything.
Here are the 9 simple points from Apple's docs to be in mind while using ARC:
ARC imposes some new rules that are not present when using other
compiler modes. The rules are intended to provide a fully reliable
memory management model; in some cases, they simply enforce best
practice, in some others they simplify your code or are obvious
corollaries of your not having to deal with memory management. If you
violate these rules, you get an immediate compile-time error, not a
subtle bug that may become apparent at runtime.
You cannot explicitly invoke dealloc, or implement or invoke retain,
release, retainCount, or autorelease.
The prohibition extends to using #selector(retain), #selector(release), and so on.
You may implement a dealloc method if you need to manage resources other than releasing instance variables. You do not have to
(indeed you cannot) release instance variables, but you may need to
invoke [systemClassInstance setDelegate:nil] on system classes and
other code that isn’t compiled using ARC.
Custom dealloc methods in ARC do not require a call to [super dealloc] (it actually results in a compiler error). The
chaining to
super is automated and enforced by the compiler.
You can still use CFRetain, CFRelease, and other related functions
with Core Foundation-style
You cannot use NSAllocateObject or NSDeallocateObject.
You create objects using alloc; the runtime takes care of
deallocating objects.
You cannot use object pointers in C structures.
Rather than using a struct, you can create an Objective-C class to manage the data instead.
There is no casual casting between id and void *.
You must use special casts that tell the compiler about object lifetime. You need to do this to cast between Objective-C objects and
Core Foundation types that you pass as function arguments. For more
details, see “Managing Toll-Free Bridging.”
You cannot use NSAutoreleasePool objects.
ARC provides #autoreleasepool blocks instead. These have an advantage of being more efficient than NSAutoreleasePool.
You cannot use memory zones.
There is no need to use NSZone any more—they are ignored by the modern Objective-C runtime anyway.
I'm looking for an easier way to manipulate audio buffers on the iPhone. Mainly I'm trying to avoid pointer issues and array count issues with C, but don't want to be slowed down by number objects like NSNumber or NSInteger which I would have to use with NSArray.
I've come across CFArray which seems like it might be a nice middle ground. Am I correct in this assumption? Or am I missing something?
Not really. CFArray is basically the same as NSArray, you can even cast between the two, this is called toll-free bridging.
CFArray (and its mutable counterpart) does allow you to specify your own callback functions for retaining and releasing the objects (pointers) in your array, which would allow you to store arbitrary pointers (not just NSObjects) in the array and implement your own memory management scheme, but I doubt that this would result in any real performance gains. For your use case, C arrays are probably the way to go.
If performance and memory size are of any concern, which they likely will be for real-time audio processing, stick to plain C arrays, and learn how to code array passing and access correctly.
You need to handle audio in C arrays anyway, as the iOS Audio Queue and Audio Unit APIs pass audio data using C arrays.
If you don't like C-style and want to use some need object oriented class-style I would really recommend to use C++, eg. std::vector or similar.
Do not use Objective-C for audio it's not made for signal processing! Obj-C is great for dealing with UI's and connecting objects within a signaling system. Any kind of 'real' computation should always be done in C or flat C++.
After not programming for a long, long time (20+ years) I'm trying to get back into it. My first real attempt is a Scrabble/Words With Friends solver/cheater (pick your definition). I've built a pretty good engine, but it's solves the problems through brute force instead of efficiency or elegance. After much research, it's pretty clear that the best answer to this problem is a DAWG or CDWAG. I've found a few C implementations our there and have been able to leverage them (search times have gone from 1.5s to .005s for the same data sets).
However, I'm trying to figure out how to do this in pure Objective-C. At that, I'm also trying to make it ARC compliant. And efficient enough for an iPhone. I've looked quite a bit and found several data structure libraries (i.e. CHDataStructures ) out there, but they are mostly C/Objective-C hybrids or they are not ARC compliant. They rely very heavily on structs and embed objects inside of the structs. ARC doesn't really care for that.
So - my question is (sorry and I understand if this was tl;dr and if it seems totally a newb question - just can't get my head around this object stuff yet) how do you program classical data structures (trees, etc) from scratch in Objective-C? I don't want to rely on a NS[Mutable]{Array,Set,etc}. Does anyone have a simple/basic implementation of a tree or anything like that that I can crib from while I go create my DAWG?
Why shoot yourself in the foot before you even started walking?
You say you're
trying to figure out how do this in pure Objective-C
yet you
don't want to rely on a NS[Mutable]{Array,Set,etc}
Also, do you want to use ARC, or do you not want to use ARC? If you stick with Objective-C then go with ARC, if you don't want to use the Foundation collections, then you're probably better off without ARC.
My suggestion: do use NS[Mutable]{Array,Set,etc} and get your basic algorithm working with ARC. That should be your first and only goal, everything else is premature optimization. Especially if your goal is to "get back into programming" rather than writing the fastest possible Scrabble analyzer & solver. If you later find out you need to optimize, you have some working code that you can analyze for bottlenecks, and if need be, you can then still replace the Foundation collections.
As for the other libraries not being ARC compatible: you can pretty easily make them compatible if you follow some rules set by ARC. Whether that's worthwhile depends a lot on the size of the 3rd party codebase.
In particular, casting from void* to id and vice versa requires a bridged cast, so you would write:
void* pointer = (__bridge void*)myObjCObject;
Similarly, if you flag all pointers in C structs as __unsafe_unretained you should be able to use the C code as is. Even better yet: if the C code can be built as a static library, you can build it with ARC turned off and only need to fix some header files.
Currently I am making some decisions for my first objective-c API. Nothing big, just a little help for myself to get things done faster in the future.
After reading a few hours about different patterns like making categories, singletons, and so on, I came accross something that I like because it seems easy to maintain for me. I'm making a set of useful functions, that can be useful everywhere.
So what I did is:
1) I created two new files (.h, .m), and gave the "class" a name: SLUtilsMath, SLUtilsGraphics, SLUtilsSound, and so on. I think of that as kind of "namespace", so all those things will always be called SLUtils******. I added all of them into a Group SL, which contains a subgroup SLUtils.
2) Then I just put my functions signatures in the .h file, and the implementations of the functions in the .m file. And guess what: It works!! I'm happy with it, and it's easy to use. The only nasty thing about it is, that I have to include the appropriate header every time I need it. But that's okay, since that's normal. I could include it in the header prefix pch file, though.
But then, I went to toilet and a ghost came out there, saying: "Hey! Isn't it better to make real methods, instead of functions? Shouldn't you make class methods, so that you have to call a method rather than a function? Isn't that much cooler and doesn't it have a better performance?" Well, for readability I prefer the functions. On the other hand they don't have this kind of "named parameters" like methods, a.f.a.i.k..
So what would you prefer in that case?
Of course I dont want to allocate an object before using a useful method or function. That would be harrying.
Maybe the toilet ghost was right. There IS a cooler way. Well, for me, personally, this is great:
MYNAMESPACECoolMath.h
#import <Foundation/Foundation.h>
#interface MYNAMESPACECoolMath : NSObject {
}
+ (float)randomizeValue:(float)value byPercent:(float)percent;
+ (float)calculateHorizontalGravity:(CGPoint)p1 andPoint:(CGPoint)p2;
// and some more
#end
Then in code, I would just import that MYNAMESPACECoolMath.h and just call:
CGFloat myValue = [MYNAMESPACECoolMath randomizeValue:10.0f byPercent:5.0f];
with no nasty instantiation, initialization, allocation, what ever. For me that pattern looks like a static method in java, which is pretty nice and easy to use.
The advantage over a function, is, as far as I noticed, the better readability in code. When looking at a CGRectMake(10.0f, 42.5f, 44.2f, 99.11f) you'll may have to look up what those parameters stand for, if you're not so familiar with it. But when you have a method call with "named" parameters, then you see immediately what the parameter is.
I think I missed the point what makes a big difference to a singleton class when it comes to simple useful methods / functions that can be needed everywhere. Making special kind of random values don't belong to anything, it's global. Like grass. Like trees. Like air. Everyone needs it.
Performance-wise, a static method in a static class compile to almost the same thing as a function.
Any real performance hits you'd incur would be in object instantiation, which you said you'd want to avoid, so that should not be an issue.
As far as preference or readability, there is a trend to use static methods more than necessary because people are viewing Obj-C is an "OO-only" language, like Java or C#. In that paradigm, (almost) everything must belong to a class, so class methods are the norm. In fact, they may even call them functions. The two terms are interchangeable there. However, this is purely convention. Convention may even be too strong of a word. There is absolutely nothing wrong with using functions in their place and it is probably more appropriate if there are no class members (even static ones) that are needed to assist in the processing of those methods/functions.
The problem with your approach is the "util" nature of it. Almost anything with the word "util" it in suggests that you have created a dumping ground for things you don't know where to fit into your object model. That probably means that your object model is not in alignment with your problem space.
Rather than working out how to package up utility functions, you should be thinking about what model objects these functions should be acting upon and then put them on those classes (creating the classes if needed).
To Josh's point, while there is nothing wrong with functions in ObjC, it is a very strongly object-oriented language, based directly on the grand-daddy of object-oriented languages, Smalltalk. You should not abandon the OOP patterns lightly; they are the heart of Cocoa.
I create private helper functions all the time, and I create public convenience functions for some objects (NSLocalizedString() is a good example of this). But if you're creating public utility functions that aren't front-ends to methods, you should be rethinking your patterns. And the first warning sign is the desire to put the word "util" in a file name.
EDIT
Based on the particular methods you added to your question, what you should be looking at are Categories. For instance, +randomizeValue:byPercent: is a perfectly good NSNumber category:
// NSNumber+SLExtensions.h
- (double)randomizeByPercent:(CGFloat)percent;
+ (double)randomDoubleNear:(CGFloat)percent byPercent:(double)number;
+ (NSNumber *)randomNumberNear:(CGFloat)percent byPercent:(double)number;
// Some other file that wants to use this
#import "NSNumber+SLExtensions.h"
randomDouble = [aNumber randomizeByPercent:5.0];
randomDouble = [NSNumber randomDoubleNear:5.0 byPercent:7.0];
If you get a lot of these, then you may want to split them up into categories like NSNumber+Random. Doing it with Categories makes it transparently part of the existing object model, though, rather than creating classes whose only purpose is to work on other objects.
You can use a singleton instance instead if you want to avoid instantiating a bunch of utility objects.
There's nothing wrong with using plain C functions, though. Just know that you won't be able to pass them around using #selector for things like performSelectorOnMainThread.
When it comes to performance of methods vs. functions, Mike Ash has some great numbers in his post "Performance Comparisons of Common Operations". Objective-C message send operations are extremely fast, so much so that you'd have to have a really tight computational loop to even see the difference. I think that using functions vs. methods in your approach will come down to the stylistic design issues that others have described.
Optimise the system, not the function calls.
Implement what is easiest to understand and then when the whole system works, profile it and speed up what's slow. I doubt very much that the objective-c runtime overhead of a static class is going to matter one bit to your whole app.