iOS compiling order - ios

It is one of my first days at iOS programming. I came from C++ and have specific silly question. How does compiler work and go through the code?
How I understand all starts with public interface, then continues to private. How implementation works? Methods? Is view controller as main function in C++ and it goes through all methods at the start?
Here is my viewController .h and .m. This program already has some other classes and action buttons. Maybe someone can explain step-by-step. Thanks.
ViewController.h
#import <UIKit/UIKit.h>
#import <Foundation/Foundation.h>
#interface ViewController : UIViewController
#end
ViewController.m
#import "ViewController.h"
#import "Deck.h"
#import "PlayingCardDeck.h"
#interface ViewController ()
#property (weak, nonatomic) IBOutlet UILabel *flipsLabel;
#property (nonatomic) int flipCount;
#property (strong, nonatomic) Deck *deck;
#end
#implementation ViewController
- (Deck *)lol
{
if (!_deck) _deck = [self createDeck];
return _deck;
}
- (Deck *)createDeck
{
return [[PlayingCardDeck alloc] init];
}
- (void)setFlipCount:(int)flipCount{
_flipCount=flipCount;
_flipsLabel.text = [NSString stringWithFormat:#"Count: %d", _flipCount];
NSLog(#"%d", self.flipCount);
}
- (IBAction)touchCardButton:(UIButton *)sender {
if ([sender.currentTitle length]) {
[sender setBackgroundImage:[UIImage imageNamed:#"cardback"] forState:UIControlStateNormal];
[sender setTitle:#"" forState:UIControlStateNormal];
}
else {
Card *randomCard = [self.lol drawRandomCard];
if (randomCard){
[sender setBackgroundImage:[UIImage imageNamed:#"cardfront"] forState:(UIControlStateNormal)];
[sender setTitle:randomCard.contents forState:UIControlStateNormal];
self.flipCount++;
}
}
}
#end

The beginning of the program code is similar to c++, it is the very c main() function.
Within your main the framework is called (by instaticating an UIApplication or subclass object) and the names of the application class and the application delegate class are handed over to the framework. The cocoa touch framework will then instantiate the application first and instantiate the delegate and assign the delegate to the application.
Typcially the first method from your program code that is invoked is the UIApplicationDelegate method application:willFinishLaunchingWithOptions: but the one that you typcially start with is application:didFinishLaunchingWithOptions:
There some preparation is set up, which is often not required especially when you work with a storyboard or when you set the main interface in your project properties. According to these properties or storyboard one view controller is the root view controller that is invoked first. For the view controllers it is quite similar. You would use NIB files or storyboards in most cases to define their UI Items and then viewDidLoad is the first method that is being invoked with regard to the root view.
Given your code you are likely to add something like this:
-(void) viewDidLoad {
[super viewDidLoad];
[self createDeck]
// here you may want to access some UIView objects in order to display your deck.
}

I don't know if you understand how c++ compiles, Objective-C is all the same.
First preprocessor translate all preprocess code(#import, #macro, etc), and then every .m file is considered a compile unit, they are compile separately in to object files without a specific order.
Then linker links all object files together.
If you don't understand what compile unit or object file are, I suggest you do more research on how preprocessor, compiler, linker works, since it is a too broad topic to explain here.

Related

iOS - adding a method to NSObject without importing the category .h file

i want to know if the following situation can be done. I have inherited a project of iOS 8. I'd like to add a method to NSObject so that all objects can see it. and I have done this already. Here is the category implementation i have created:
#import "NSObject+myCategory.h"
#implementation NSObject (myCategory)
-(void)localizeStringIncludeDefault{
NSLog(#"about to localize String");
}
#end
Now i go to a MyViewController.m for example and try to call the method but its not working its not seen:
heres the .h:
#import <UIKit/UIKit.h>
#interface MyViewController : UIViewController {
BOOL someFakeBoolean;
IBOutlet UIView *someView;
//etc
}
#property (nonatomic,assign) IBOutlet MyViewController *myViewController;
-(void)localizeStringIncludeDefault;
and here is the implementation *.m and my issue:
#implementation MyViewController
- (void) viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
[self localizeStringIncludeDefault] //this call cant be done, the method is not visible
}
- (void) viewDidDisappear:(BOOL)animated
{
//etc
}
//etc
I mean it makes sense to me that i'd have to import the "NSObject+myCategory.h" into the MyViewController header to use the category but because i've inherited this code it already has a base. I dont want to go into every .h file and import this. Is a easy way to extend object so that EVERY object class sees my method ?
One option would be to add the category .h file to the pch file. Then it will be seen by every class in your project without the need to import it explicitly.
Declare your global variables or declarations in your pch file or rather make a Global.h and just import this in your pch file (helps a lot in reusability). You can declare extern items as well in your Global.h and populate in App Delegate

When adding UIView instantiated with an .xib to the Storyboard buttons don't work and background color can't be changed

I am working on an iOS project and wanted to include a UIView that is reused on multiple screens in the application (appearing at the bottom of different UIViews). I am using a storyboard for the UI work so far but created an .xib file to be used by the reusable view (playerView in code below).
The view gets added but the button I have added to the View is unresponsive, also my background color cannot be changed on the view. I have tried to set background color programmatically and in the .xib with no luck. Very weird symptoms and I tried to instantiate the view from #5 of this article and probably did something wrong. I dont fully understand everything in the article which makes me nervous - for instance my showSubclassedView method returns IBAction but I just call the function name in code and dont use a button (I did hook up the buttons in the view as the article described though).
Here is the code:
EventViewController.m (where I trry and add PlayerView)
#import "EventViewController.h"
#import "PlayerView.h"
#interface EventViewController ()
-(IBAction)showSubclassedView;
#end
#implementation EventViewController
-(IBAction)showSubclassedView
{
[PlayerView presentInViewController:self];
}
PlayerView.h (.h for reusable view)
#import <UIKit/UIKit.h>
#import "Utils.h"
#class PlayerView;
#protocol PlayerViewDelegate
-(void)playerViewTouchedUp:(PlayerView*) playerView;
-(void)playerViewDidDismiss:(PlayerView*) playerView;
#end
#interface PlayerView : UIView
+(void)presentInViewController:(UIViewController<PlayerViewDelegate>*) playerView;
-(IBAction)viewTouchedUp;
-(IBAction)dismiss;
#end
PlayerView.m (.m for reusable view)
#import "PlayerView.h"
#interface PlayerViewOwner : NSObject
#property(nonatomic,weak) IBOutlet PlayerView *playerView;
#end
#implementation PlayerViewOwner
#end
#interface PlayerView ()
#property (nonatomic, weak) UIViewController <PlayerViewDelegate> *delegateViewController;
#end
#implementation PlayerView
+(void)presentInViewController:(UIViewController<PlayerViewDelegate> *)viewController
{
PlayerViewOwner *owner = [PlayerViewOwner new];
[[NSBundle mainBundle] loadNibNamed:NSStringFromClass(self) owner:owner options:nil];
owner.playerView.delegateViewController = viewController;
[viewController.view addSubview:owner.playerView];
}
-(IBAction)viewTouchedUp
{
//forward to delegate
NSLog(#"you clicked a button");
[self.delegateViewController playerViewTouchedUp:self];
}
-(IBAction)dismiss
{
[self removeFromSuperview];
// Forward to delegate
[self.delegateViewController playerViewDidDismiss:self];
}
#end
PlayerView.xib has a UIbutton on it that connects it to viewTouchedUp method in PLayerView.m
Is there anything I did wrong in the code above? Is this the best way to do a reusable view to display on other views?
Thank you!
Here's a workaround I found after not being able to solve this.
New implementation is from this article
I reverted my changes from my initial question and implemented this. It lacks the nice protocol separation for talking back and forth and I might need something like this later but I think now I can still implement a protocol to solve this.
At least with this solution I have usable items in my view and a background that changes!

UITapGesture target not retained (with ARC)

I create an UITapGesture with a target which is NOT the current object. Later, when tapping, app crashes.
View controller .h:
#interface ViewController : UIViewController
{
IBOutlet UIImageView *iv;
}
#end
View controller .c:
#import "ViewController.h"
#import "Target.h"
#implementation ViewController
- (void)viewDidLoad
{
[super viewDidLoad];
Target *t = [[Target alloc] init];
UITapGestureRecognizer *tgr = [[UITapGestureRecognizer alloc] initWithTarget:t action:#selector(gestureDone:)];
[iv addGestureRecognizer:tgr];
[iv setUserInteractionEnabled:YES];
}
#end
Target.h:
#interface Target : NSObject
- (void)gestureDone:(UIGestureRecognizer *)gr;
#end
Target.c:
#implementation Target
- (void)gestureDone:(UIGestureRecognizer *)gr
{
NSLog(#"Gesture!");
}
#end
(My XIB file just contains one image...)
When tapping the image, it crashes. If for example I add an instance variable Target *t to my view controller (and remove local declaration in viewDidLoad), then no issue arises. When not doing that, I overrided dealloc in Target, put a NSLog there and saw that as soon as viewDidLoad finishes execution, the Target object is fred.
Am I doing anything wrong, or is it some issue? (Usually I'm not facing this problem because I use initWithTarget:self ...).
UIGestureRecognizer doesn't retain its target. Most objects that take a target/action pair do not retain their targets. This is mentioned in the Cocoa Fundamentals Guide/Communicating with Objects/The Target-Action Mechanism/The Target:
Control objects do not (and should not) retain their targets. However, clients of controls sending action messages (applications, usually) are responsible for ensuring that their targets are available to receive action messages. To do this, they may have to retain their targets in memory-managed environments. This precaution applies equally to delegates and data sources.
You need to make sure the target is retained some other way, such as by storing a reference to t in an instance variable of your ViewController.
Add an instance variable of the Target t to your ViewController class and make it strong. That way it stays in memory.

getting signal SIGABRT in first IOS project, Xcode 4

I am trying to create my first test app in IOs and everything I do gets me that error. I am using xcode 4.4.
The app is very simple. It has a button, and When I press it, a label and an imageview must appear.
My whole code is this:
ViewController.h
//
// ViewController.h
// helloWorld_04
//
//
#import <UIKit/UIKit.h>
#interface ViewController : UIViewController{
IBOutlet UILabel *label;
IBOutlet UIImageView *Kant;
}
#property (nonatomic, retain) IBOutlet UILabel *label;
#property (nonatomic, retain) IBOutlet UIImageView *Kant;
- (IBAction)buttonGuess:(id)sender;
#end
and my implementation file:
#import "ViewController.h"
#interface ViewController ()
#end
#implementation ViewController
#synthesize label,Kant;
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
return (interfaceOrientation != UIInterfaceOrientationPortraitUpsideDown);
}
- (void)dealloc {
[label release];
[Kant release];
[super dealloc];
}
- (IBAction)buttonGuess:(id)sender {
label.text=#"Hello World i am back!";
UIImage *imageSource=[UIImage imageNamed:#"kantStair.png"];
Kant.image=imageSource;
}
#end
My error log is this:
2012-08-23 13:38:50.030 helloWorld_04[537:c07] *** Terminating app due to uncaught exception 'NSUnknownKeyException', reason: '[<ViewController 0x6a5e1f0> setValue:forUndefinedKey:]: this class is not key value coding-compliant for the key image.'
*** First throw call stack:
(0x14b2022 0xeb2cd6 0x14b1ee1 0x9c3022 0x934f6b 0x934edb 0x94fd50 0x23771a 0x14b3dea 0x141d7f1 0x23626e 0xdc1fc 0xdc779 0xdc99b 0x3b401 0x3b670 0x3b836 0x4272a 0x2d1b 0x13386 0x14274 0x23183 0x23c38 0x17634 0x139cef5 0x1486195 0x13eaff2 0x13e98da 0x13e8d84 0x13e8c9b 0x13c65 0x15626 0x2a22 0x2995)
terminate called throwing an exception(lldb)
and it gets me that signal in that line:
//
// main.m
// helloWorld_04
//
//
#import <UIKit/UIKit.h>
#import "AppDelegate.h"
int main(int argc, char *argv[])
{
#autoreleasepool {
return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
}
}
I have read several answers here but not found sollution to my problem, that why I made it a new question. I thought that it may be a problem with the connection so what I did on my own was to "darg and drop" my label and my image to "file's owner" but still getting the error.
Looking at your error message, it looks like you have something defined as image in Interface Builder, but doesn't exist. E.g., maybe you have something like:
But you don't have a image property. Did you have one once upon a time, perhaps having renamed it to Kant? If you have something like this defined in Interface Builder, delete it (by tapping on the "x" next to the outlet that I've highlighted) and then link it up again to your new control.
Update:
You should definitely fix your bug above, and hopefully the above observation helps you find it. There is not a bug in your code, but rather the problem undoubtedly rests with your Interface Builder linkages.
But, having said that, if you're a new programmer, I hope you don't mind some unsolicited stylistic observations. Clearly, given that it is a matter of style, these can be debated, but I think these all represent either established or emerging iOS coding standards. Anyway, I might suggest that in the future:
Like David H suggested, you should use lower case variable names.
You probably should have #synthesize statements that either say #synthesize label = _label, or, if you're using Xcode 4.4 or later, just omit the #synthesize statement altogether. (I know that Interface Builder can generate a simple #synthesize statement for you, but it really is best practice to #synthesize with a unique instance variable name so you don't accidentally confuse instance variables with properties.)
You should reference your instance variables in init and dealloc methods (i.e. the variable name with the leading underscore) and elsewhere use the property (with the leading self.), as noted by Born Survivor.
You probably should omit the instance variables and let the #synthesize statement do these for you (so that if you make a typo, you don't accidentally end up with two instance variables).
Thus your code would then become:
// ViewController.h
#import <UIKit/UIKit.h>
#interface ViewController : UIViewController
// note, no braces with instance variables defined
// once upon a time that was recommended by Apple, but no longer
// just let the following #property statements and the subsequent
// #synthesize statement generate the instance variables for you.
#property (retain, nonatomic) IBOutlet UIImageView *kant; // note the lower case "k"
#property (retain, nonatomic) IBOutlet UILabel *label;
- (IBAction)buttonGuess:(id)sender;
#end
and
// ViewController.m
#import "ViewController.h"
#implementation ViewController
#synthesize label = _label; // note the #synthesize statement let's us define what the instance variable name should be, _label in this case
#synthesize kant = _kant;
- (void)viewDidUnload
{
[self setKant:nil];
[self setLabel:nil];
[super viewDidUnload];
// Release any retained subviews of the main view.
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
return (interfaceOrientation != UIInterfaceOrientationPortraitUpsideDown);
}
- (void)dealloc {
[_kant release]; // note I'm now using the instance variables that begin with the underscore
[_label release];
[super dealloc];
}
- (IBAction)buttonGuess:(id)sender
{
self.label.text = #"Hello World i am back!"; // note, I'm using the properties with the preceding "self."
UIImage *imageSource = [UIImage imageNamed:#"kantStair.png"];
self.kant.image = imageSource;
}
#end
Its important in ObjectiveC to always name your variables with a lower case letter - because when you synthesize a variable like "foo" you get "-(id)foo;// the getter" and "-(void)setFoo:(id)val;//the setter". See how the setter uses a capital letter. So first thing you should do is rename 'Kant' to 'kant'. [by convention only Classes have initial capital letters, so you help others like me read your code by following the conventions.]
So first thing you do is change 'Kant' to 'kant', and then go back to the Interface builder view and re-wire the newly named variable to the UIImageView.
If that does not fix the problem, you have iswired 'kant' or there is some other oddity going on - add this line of code right before you set the image:
NSLog(#"kant has class %#", NSStringFromClass([kant class]) );
and lets see what it really is.

IBAction Play an MP3

I have an App that I am making thatis similar to Urbanspoon. I have a picker the spins and it is hooked up to an IBAction for a UIButton. I want a mp3 file to play once the button is pressed. I feel it will give the user more of an experience by doing this.
I imported the AVFoundationFramework and the AudioToolBoxFramework and imported their .h into my main .m file
Here is my action.
- (IBAction)spinTheSpinner:(id)sender {
if ([sender isSelected]) {
[sender setImage:[UIImage imageNamed:#"GoldTapButton.png"] forState:UIControlStateNormal];
[sender setSelected:NO];
}
else {
[sender setImage:[UIImage imageNamed:#"PurpleTapButton.png"] forState:UIControlStateHighlighted];
[sender setSelected:YES];}
[picker1 selectRow:(arc4random() % [self pickerView:picker1 numberOfRowsInComponent:0]) inComponent:0 animated:YES];
}
Do i need to make a separate action for the same button or can i just add a block of code into this same action. I have the mp3 file is my resources folder so its in my project I just cant find where and what to do to make it happen.
Here is my .h as well just for good measure
#import <UIKit/UIKit.h>
#import<AVFoundation/AVAudioPlayer.h>
#interface ViewController : UIViewController
- (IBAction)spinTheSpinner:(id)sender;
#property (nonatomic, retain) NSMutableArray *picker1Data;
#end
also here is the top of my .m file
#import "ViewController.h"
#import "Twitter/Twitter.h"
#import "UIKit/UIKit.h"
#import"AVFoundation/AVAudioPlayer.h"
#interface ViewController ()
{
#private
UIPickerView *picker1;
}
#end
#implementation ViewController
Any help or suggestion or code would be a huge help in any way. I am running on a bit of a time schedule. THANKS S.O
Yes you can just add the code into the same IBAction method. You re not limited to th amount of code you can run in the method its currently linked to

Resources