I want to create a lite version of my app. When I searched on google, almost all the solutions mentioned to create a duplicate target and set necessary flags (to differentiate between full and lite version).
Now I did the necessary things but in my lite app I want some controls in one scene to be disabled. So how do I do it in the design mode?
With the flag sets I can differentiate between full and lite app while Runtime. But can I make the changes to a scene only for lite app in Design Time?
Or for every scene load, I'll have to check the flag and then do the disable/enable code in runtime.
What are my options? Please help.
I think the most manageable way is in your code. One example:
- (void)viewDidLoad {
[super viewDidLoad];
if (kIsLiteVersion) {
[someObject setEnabled:NO];
}
}
Or, perhaps you'd do this in init in some cases (maybe you want to not create certain objects in the lite version). Or, maybe use the condition to determine which storyboard view controller to push in some cases, and have some for the lite version.
Related
i am totally new to iphone and i am trying to create a universal app.
Now I am creating an empty application. According to all tutorials , by checking universal option it should auto create appdelegates for both iphone and ipad.
But all i can see is only one appdelegate . Kindly tell me how can i create both.
Best Regards
Brayden is correct in answering that you almost never need multiple app delegates. All the delegate usually does is handle the moments when the application launches, suspends or terminates. Back in the days when iPhones ran iOS 4.0, and iPads ran iOS 3.2, you might need very different code in the delegate because only iOS 4.0 supported multitasking. Those days are long gone, and your delegate should probably act the same on all devices.
Yes, you sometimes do reach a point where your program must behave differently on iPhone and iPad. Check the idiom at that time and no earlier. Otherwise you're just duplicating code to no purpose.
My most recent app contains almost no special checks for iPhone or iPad. It doesn't even use different XIBs. Instead, my custom views implement layoutSubviews to fill the space available.
That said, once you understand app delegates, maybe you will find a situation where you need them to be different. If you are absolutely certain that your iPhone and iPad behavior will be so wildly divergent, you will need to:
Manually create a new class (preferably inheriting from the existing AppDelegate class)
In your main.m, send the class name of your new delegate to UIApplicationMain depending on the idiom.
See this answer to "Can I create App Delegate file in my project?" to see the changes to main.m.
You really should only be using one AppDelegate for a Universal application. You can use this to share common things that you'll do in there. What exactly do you need multiple AppDelegates for? If you need to do something specific to a device type (i.e. - iPhone or iPad) then you can do a ternary expression like below:
(UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) ? NSLog(#"iPad") : NSLog(#"iPhone");
I am creating a Universal iOs application as part of an assignment (iPad and iPhone :) ).
Naturally, they have a UI which I have been accustomed to create through the NIB files, using the fancy drag and drop schemes. This obviously seems like a great strategy when you are making a dedicated iOS device application.
However, with the universal application, I notice that this strategy can be a challenge since the 2 UIs differ and human error can promote a lack of consistency in the two UI's + double the work!!!
I noticed the solution to the assignment I am doing has the UI created through the AppDelegate file, I have never really done this, and from this stems the questions:
What is the appDelegate files for anyways?
Is it the way to create the UI for the Universal application through the App delegate? Or do you people still create the UI's through the NIB files meticulously for both iPhone and iPad?
P.S: Side question: This assignment requires me to create a Windows based application vs a View based application which is what I have naturally learnt to do. I understand a Windows based App can grow into a view based application and vice versa. However, I do not understand when you should choose to create a Windows based application?
The AppDelegate in Cocoa is your central Singleton that controls the app workflow. It's used by the underlying Framework to start the application, signal runtime envrionment changes and terminate the app. Being a singleton, it's always there and easy to reference ([UIApplication applicationDelegate]) and it loads up your first view controller.
It's generally common to let the application delegate keep refernces to model and controller objects. But what you describe, the whole UI programmed through the appDelegate, is bad style.
No matter if you use NIB's or you code your UI by manually adding UIElements to the view in code, you should do so in ViewController. Generally, the appDelegate will call the first view controller and that viewcontroller will call all view controller afterwards.
I have a bunch of xib files that I use in my app's full version. In the lite version I want to be able to load some xibs that have less features, thus making it a lite version. All my viewControllers are hooked up in IB, and are referenced by both targets at the moment.
What's the best way to hide functionality beyond simply disabling it? I figured that having an entirely different xib file would be easiest, am I wrong?
Edit:
To clarify, I'm trying to figure out how to load a different nib for a view controller depending on the version. I believe it has something to do with initWithNib.
Use targets, you can exclude/include files per target.
Create a target for lite, which does not include some parts that the full app wil, like load a NIB which has les functionality than the full version.
You can even use the same names for code files (.m) and NIB and include/exclude via the target property.
This will only work if you have a lite and full version in the app store.
If you want a in app purchase then you will need to do what #Jack Humphries suggests.
Yes, you are right, having different XIBs in my opinion would be easier. So, the full and lite versions are in the same app with an in app purchase? I would have a generic home page, and then use NSUserDefaults to link to different pages. For example, here is the code for a button:
-(IBAction)gotogame {
if ([[NSUserDefaults standardUserDefaults] boolForKey"#Purchased"] == YES) {
//go to the entire game XIB
}
else {
//go to the lite game
}
Here is how you set NSUserDefaults:
[[NSUserDefaults standardUserDefaults] setBool:YES forKey"#Purchased"];
Additionally, if you want everything in the same view, use NSUserDefaults, and if the Purchased key is equal to yes, then do this:
[litePicture setHidden:YES];
[fullPicture setHidden:NO];
And vice versa. Let me know if you have any questions!
I have an iPad app that I would like to make Universal, however this seems alarmingly difficult. I've changed things around so that I support both builds, but when building, I get lots of errors about using UIPopOvers. Here're my questions:
Why does UI_USER_INTERFACE_IDIOM() not compile or register on 3.1.3?
Can I conditionally have variables in a class definition based on UI_USER_INTERFACE_IDIOM()?
If not, should I make two different view controllers?
Thanks!
Why does UI_USER_INTERFACE_IDIOM() not
compile or register on 3.1.3?
The UI_USER_INTERFACE_IDIOM macro is only available starting with 3.2. Same restrictions for the userInterfaceIdiom property of UIDevice. This means that you can only get universal application starting with SDK 3.2.
Can I conditionally have variables in
a class definition based on
UI_USER_INTERFACE_IDIOM()?
No. The UI_USER_INTERFACE_IDIOM macro is only a runtime shortcut to get the current UI idiom of the device.
If not, should I make two different
view controllers?
If you have very different UI between the two devices, it is wiser to use two different view controllers, and to create the right one at runtime (in the application controller for example) by using the UI_USER_INTERFACE_IDIOM macro.
I had pretty good luck with just selecting the target then going to Project->Upgrade current target for iPad.
My app is pretty simple, consisting mostly of table views and webviews, but it's worth making a backup and trying...
And yes, you have to submit it as a 3.2 app that can target 3.1.*
There are also a lot of other stuff that you have to do:
Make sure that it can be viewed at any orientation (got rejected the first time for this).
Make sure that you have all the new images created. you have to have 3 or 4 icons, instead of just one like an iPhone app needed. (iPad icon, iPhone icon, small icon for spotlight, etc).
And of course iPad sized screenshots for the store.
A really nice way that I use to test if it's an iPad or iPhone is to check if the device can use a split view controller, since for the forseeable future no device with a screen as small as an iPhone will be able to use the split view controller. I just created a function to do this for me:
+(BOOL)isIpad{ return NSClassFromString(#"UISplitViewController") != nil; }
Then anywhere in my app that I want to display something different depending on device, I just do a check for it:
int width = 150;
if([NabAppDelegate isIpad]){
width = 350;
} else {
width = 150;
}
UILabel *label = [[UILabel alloc] initWithFrame:CGRectMake(5,10,width,25)];
This is a lot better than checking against OS version like I've seen some suggest.
I am about to create a Cocoa app and I want to ensure that one day I can easily port it to the iPad or even the iPhone. How can I plan for this in advance?
I know I will have to redo all NIBs and probably design a different workflow.
But what about the code? Just replacing every NSsomething with UIsomething won't cut it, right? Any tips on how to make sure now that I won't shoot myself in the foot later?
Thank you!
(The iPad-SDK is under NDA. For the sake of this question just assume i asked about the iPhone, OK? Or think iPhone with a bigger screen.)
Make sure you strictly uphold the Model-View-Controller separation in your app. The model, especially, should never depend on any controller or view.
In porting to the iPhone/iPod touch/iPad, you'll need to replace most or all of the controllers and all of the NSViews and NSCells. You should be able to keep your CALayer subclasses, if you have any. You may be able to reuse one or two controllers with conditional compilation, if most of a controller will work on both but some parts only work on the Mac or work on both but with completely different APIs. And you should be able to keep the entire model unchanged.
There are probably some more specific pitfalls that an iPhone developer can warn you about, but this is the general rule that holds for any transition from one environment to another. (An example of another environment transition would be making one or more command-line tool equivalents or complements to your app, like xcodebuild, packagemaker, or ibtool.)
Also, look at the Introduction to the Foundation framework reference for figures showing which Foundation classes are Mac- and iPhone-only.
A lot of libraries aren't even supported in Cocoa Touch versus the desktop Cocoa libraries. You need to consider the differences in AppKit versus UIKit. Also, Objective-C does not allow garbage collection on the iPhone. There are many touch events that only exist on the iPhone but not on a desktop. iPhone development is much more restrictive due to the fact that a phone is a very personal device tied to very personal data.
Check out these slides for a better comparison: http://www.slideshare.net/lukhnos/between-cocoa-and-cocoa-touch-a-comparative-introduction
As with any good project layout, you should separate out your UI from your non-UI components. That doesn't just mean on disk layout (though that makes sense as well) but rather using a MVC approach, whereby your controllers (C) know about the Models (M) and the UI (V) is rendered separately.
You can use Key-Value Observing (aka KVO) to set up your models, such that when they fire, it sends around a notification to any registered listeners to update. If you are using XIB to generate your user interfaces, then this is what happens when you bind an object to your display widget(s).
So you can end up with separate XIBs for your iPhone, Mac OS and (later) iPad - though if you resize things correctly, you can have the same XIB for the iPhone and iPad.
Lastly, there are often some cases where you need to inject logic into your models (for example, adding an image to return from a method). In this case, the iPhone and Mac OS have different Image classes. To do this, you can create the following:
MyModel.m // contains the data, no UI
MyModel+UIImage.m // contains a category for adding the UIImage
MyModel+NSImage.m // contains a category for adding the NSImage
The category looks like this:
#interface Host(UIImage)
-(UIImage *)badge;
#end
#implementation MyModel(UIImage)
-(UIImage *)badge
{
if (green)
return [UIImage imageNamed:#"green.png"];
if (red)
return [UIImage imageNamed:#"red.png"];
}
#end
---
#interface Host(NSImage)
-(NSImage *)badge;
#end
#implementation MyModel(NSImage)
-(NSImage *)badge
{
if (green)
return [[NSImage alloc] initWithContentsOfFile: #"green.png"];
if (red)
return [[NSImage alloc] initWithContentsOfFile: #"red.png"];
}
#end
This has the added advantage that your unit tests can just load the model (without any image categories being loaded) whereas at runtime your code that needs to process the images (say, in a view controller) can load the model-with-category and load the badge with [model badge] in a transparent way, regardless of which platform it's compiled for.