KIF (Keep It Functional) distinguish between iPhone and iPad - objective-c

I am using KIF for testing the functionality of an app. However, this app has two versions, one is for iPad, and the other one is for iPhone. Is there a global variable or something that indicates if I am running my test in iPad or iPhone? I'd like to use it (e.g. in a conditional) to take advantage and just make a few modifications in the iPhone tests that I have already finished.

You can define macro
#define IS_IPAD (UI_USER_INTERFACE_IDIOM() != UIUserInterfaceIdiomPhone)
That's how we used it.

Related

Change iOS Simulator Device Name

I'm working on a big project with many view controllers. Progression through these views depends on data being filled in on lengthy forms.
In my not-so-clever way i'm autofilling data so that i can speed through to the current feature I'm working on. I was using a conditional like this...
if(
[[[UIDevice currentDevice] name] hasPrefix:#"Rob"] ||
[[[UIDevice currentDevice] name] hasPrefix:#"iPad Simulator"]
)
{
self.label.text = #"xxx";
...
}
...this worked great because I could test both on my iPad and in the simulator. Now the client wants to also be able to test on their simulator, so I can't leave my autofill in. I'm thinking the simplest solution would be to just change the name of the simulator.
In Settings.app on the simulator, it's not editable. I also haven't seen then text "iPad Simulator" or "Simulator" show up in any files in ~/Library/Application Support/iPhone Simulator/5.1. I've done searches on setting plist properties, but no luck.
Does anyone know how to accomplish this?
You'll be able to check if it's running the iPhone Simulator by checking the model rather than the name of the current device. Something like the following should do:
if ([[[UIDevice currentDevice] model] isEqualToString:#"iPhone Simulator"]) {
// Run for iPhone simulator
}
Note: You'll need to use "iPad Simulator" for when you use the iPad Simulator
Also, your current code with hasPrefix is not secure at all. Rob is a common name so if someone else has a device with the name of their device beginning with Rob then it'll expose your test information. I highly suggest you just target this autocomplete for the simulator only
Just create a new class and put your loading logic there.
After that, call this class from your delegate didFinishLaunchingWithOptions method.
With this, you can comment the above call whenever you want or better, check if the data is already loaded and ignore it.

How do you programmatically detect your iPad's generation?

I'm working on a program that needs to be able to detect whether or not camera hardware is present in the iPad. I assumed that the easiest way to do this was to determine what generation the device was, but if there is a simpler way to detect the hardware that works too. The iPads that this application is being designed for will likely be recently purchased and running on a standard updated version of iOS.
Nope You can simply check what device is being used!
For checking all iOS devices:
NSString *deviceType = [UIDevice currentDevice].model;
NSLog(deviceType);
In order to check for a camera
if ([UIImagePickerController isSourceTypeAvailable: UIImagePickerControllerSourceTypeCamera])
//there is a camera

Sound does only work on Device but not in Simulator

I am playing some short sounds on my iPad like so: Play a short sound in iOS
I am using a caf file which I can successfully play from the Finder. Now I went through quite a bit of a hassle trying to achieve the playback of the sound and I am curious what might be the problems which I don't seem to understand:
Option 1: When I create the SystemSoundID and then play it right away I don't hear anything on the device and the simulator.
Option 2: When I create an instance variable for the SystemSoundID and initialize it in viewDidLoad I manage to play sound but only on the iPad, not the Simulator.
Option 3: Instead of using SystemSoundID I can also use AVAudioPlayer to playback a .wav file which then works on both the iPad and the Simulator but here I need to create the AVAudioPlayer in viewDidLoad otherwise I won't get any sound if I do everything in one go.
The best option currently seems to be Option 3 because it works on both the Simulator and the iPad, but because I need to pre-initialize the Player I would need an AVAudioPlayer instance for every different sound that I want to play, which does not seem to be very memory-wise...
Is there something that I am missing and is it possible to play sounds on both platforms using the AudioToolbox framework (Option 1 & Option 2)
I wrote a library to simplify all this. It wraps AVAudioPlayer, and works fine on both the device and simulator.
https://github.com/nicklockwood/SoundManager
The code is fairly straightforward, although I do some semi-clever stuff to initialise the audio player. If you don't want to use the library you can just copy the code.
A word of warning though - the simulator throws some odd exceptions internally whenever you use AVAudioPlayer. They don't affect the app at all, but if you have enabled break-on-exceptions in Xcode then the app will drop into the debugger a few times during startup and you'll have to manually resume, which may freak you out if you're not expecting it.

Create single .xib for Universal app in Interface Builder? (iOS)

Apologies if this is a silly question, but I've done some googling and searched SO and haven't found anyone asking this exact question.
I have been doing iOS development for some time now, but I am completely new to the Interface Builder. What I want to know is this: is there any way to just create ONE .xib file and then use it for both iPhone and iPad in a Universal application?
It seems silly to me to have to create them separately; why do twice the work laying something out more than once in Interface Builder when I could do it once (with minor adjustments for screen size) in code?
Please let me know if I'm missing/misunderstanding something here. Like I said, I'm a complete Interface Builder newbie :)
EDIT: I have submitted non-interface-builder games to the App Store in the past where the iPhone and iPad versions were identical, so I'm not concerned with making the game look/feel different on each device. I intend for them to look exactly the same, aside from some slight positioning changes due to the difference in aspect ratio.
If you know what the resulting view would look like, based on autoresizing, you can indeed use only one .xib. May come in handy if the view is just some sort of a shared component that autoresizes as you want it to. However, if you need the view to look way different on iPad than on iPhone, just use two .xibs. It’s possible then to load the appropriate one as needed, for example in instance initializer, like this controller’s -init:
- (id)init
{
if ([UIDevice currentDevice].userInterfaceIdiom == UIUserInterfaceIdiomPad)
{
self = [super initWithNibName:#"YourNibForPad" bundle:nil];
}
else
{
self = [super initWithNibName:#"YourNibForPhone" bundle:nil];
}
if (self) { /* initialize other ivars */ }
return self;
}
The main reason that XIBs are separate files is because Apple feel that UIs designed for iPhones/iPod touches and iPads should be tailored to each respectively. This is echoed in their their iOS App Programming Guide, which says the following:
For views, the main modification is to redesign your view layouts to support the larger screen. Simply scaling existing views may work but often does not yield the best results. Your new interface should make use of the available space and take advantage of new interface elements where appropriate. Doing so is more likely to result in an interface that feels more natural to the user—and not just an iPhone app on a larger screen.
Whilst it can take time to maintain two XIBs for what is effectively one UI, I feel it is more straightforward than using one XIB and then having to connect up most of your UI elements in order to move them around programmatically when that XIB loads. After all, with two XIBs at least you can see what each UI looks like, and then make visual changes easily.
As an aside, don't forget iOS 5's Storyboards (read about them here), which make managing a view/view controller hierarchy much simpler.
Try to name them
MyCell.xib and MyCell ~ ipad.xib
then:
[self.tableView registerNib: #"MyCell" forCellReuseIdentifier: #"MyUniqueIdentifier"];
If your using IB, you need to create 2 separate xib files for iPhone and iPad. You need a separate iPad xib to make your app comply with the Apple iPad UI guidelines.

Better way to detect if isIpad?

I have an universal app that changes the screen layout based on what device the user has.
It seems to work pretty good, but I've had one user call in (and send me screen shots) of his iPhone 4 showing him the iPad view instead of the iPhone view. I haven't been able to duplicate it on any of the phones we have around here, but I'm wondering if there there is a better way to do this since iOS 4.3 has come out.
+(BOOL)isIpad{
return ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPad);
}
Alternately, is there just a way to detect screen size? I mostly use this to determine how wide elements in a table should be, but if Apple comes out with iPad 3 with retina display, it would be nice to have the app just adjust everything accordingly.
Also useful if the app is in portrait or landscape. Make it so that it just anchors to the edges like elements in WPF.
When loading XIBs for a universal app this, or what you're already doing, seems to be the only way:
NSString *xibName = (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad)?#"SomeView~iPad":#"SomeView";
As for screen size this should work:
CGRect screenSize = [[UIScreen mainScreen] bounds];
This is like a bazillion years old, but came across it in google so I figured I'd post a poorly documented but very useful feature. If you add ~ipad to the end of the filename for your iPad specific nib it will automatically load that one instead. Same logic as #2x for loading images. So your iPhone nib would be named myview.xib and your ipad myview~ipad.xib and iOS will correctly load the ipad version wherever needed. Fancy!
UIUserInterfaceIdiomPad is now deprecated. The new way to do it would be using TraitCollections. It can only be called on Views.
-(BOOL) isiPad{
return self.view.traitCollection.horizontalSizeClass == UIUserInterfaceSizeClassRegular && self.view.traitCollection.verticalSizeClass == UIUserInterfaceSizeClassRegular;
}
Refer Apple Documentation here
Probably it has a previous version of the app and conflict with the new!
Try to remove old one and reinstall new! It works! I already encountered this issue.