Best iphone questions in May 2012

How to restart app if it unexpectedly shutdown

17 votes

Skype update text contains next:

App auto restarts if unexpectedly shut down

How is possible to perform that via SDK?

As far as I know, some sort of apps can be run in background and can be restarted in specific case. This is from Apple docs

https://developer.apple.com/library/ios/#documentation/CoreLocation/Reference/CLLocationManager_Class/CLLocationManager/CLLocationManager.html#//apple_ref/doc/uid/TP40007125

If you start this service and your application is subsequently terminated, the system automatically relaunches the application into the background if a new event arrives. In such a case, the options dictionary passed to the application:didFinishLaunchingWithOptions: method of your application delegate contains the key UIApplicationLaunchOptionsLocationKey to indicate that your application was launched because of a location event.

My opinion is: Skype is relaunched with remote notifications mechanism.

Update

Well, I think I found something. @Malek_Jundi was half-right. Your app should fail with non-zero exit code, but it should be registered as VoIP application.

Because VoIP applications need to stay running in order to receive incoming calls, the system automatically relaunches the application if it exits with a nonzero exit code. (This could happen in cases where there is memory pressure and your application is terminated as a result.) However, terminating the application also releases all of its sockets, including the one used to maintain the VoIP service connection. Therefore, when the application is launched, it always needs to create its sockets from scratch.

http://developer.apple.com/library/ios/#documentation/iPhone/Conceptual/iPhoneOSProgrammingGuide/AdvancedAppTricks/AdvancedAppTricks.html#//apple_ref/doc/uid/TP40007072-CH7-SW12

Implementing Non -Renewable subscriptions Using MKstorekit4?

16 votes

I have Iphone application in which i wanted to use Non_Renewable subscriptions.As per docs MKstorekit supports Non Renewable subscriptions.But everywhere saying about Auto_renewables only.Can anybody knows how to implement Non-renewable subscription with MKstorekit4.I have been googling for the entire day.But with no luck.Can anybody help me ?Was anybody done this kind of in app with mkstorekit?

In non renewing subscriptions we need to use the server tracking .In non renewing subscriptions you will get a reciept data containg some purchase details with purchase date,store the reciept in your server and calculate the exp date from the purchase date and use this server tracking to show your buying view again,you need to store the reciept corresponding with the user details to get this on all the deices the user is using

Is there any way other than thumbnail method to take a screenshot of an video in Iphone?

11 votes

Is there any way other than thumbnail method to take a screenshot of an video? If yes then please tell me if not then please tell me how to resize an thumbnail image with a same resolution? i have getting an issue while taking screenshot of video.i have used this:-

How to take a screenshot from an video playing through MPMediaPlayerController in iPhone?

After this i ve used merging of an image by which i'm getting thisResolution problem

here image quality is my big issue.

I want this

Required Output

I want only video and drawing shown in above screenshot with same resultion. Please help Thanks :)

There is a way other than thumbnail method by which i can get screenshot of a video.!!!

The way is this :-

- (UIImage *)imageFromVideoURL 
{
// result 
UIImage *image = nil;

// AVAssetImageGenerator
AVAsset *asset = [[AVURLAsset alloc] initWithURL:appDelegate.videoURL options:nil];; 
AVAssetImageGenerator *imageGenerator = [[AVAssetImageGenerator alloc] initWithAsset:asset];
imageGenerator.appliesPreferredTrackTransform = YES;

// calc midpoint time of video
Float64 durationSeconds = CMTimeGetSeconds([asset duration]);
CMTime midpoint = CMTimeMakeWithSeconds(durationSeconds/2.0, 600); 

// get the image from 
NSError *error = nil; 
CMTime actualTime;
CGImageRef halfWayImage = [imageGenerator copyCGImageAtTime:midpoint actualTime:&actualTime error:&error];

if (halfWayImage != NULL) 
{
    // cgimage to uiimage
    image = [[UIImage alloc] initWithCGImage:halfWayImage];
    [dic setValue:image forKey:kImage];
    NSLog(@"Values of dictonary==>%@", dic);
    NSLog(@"Videos Are:%@",appDelegate.videoURLArray);
    CGImageRelease(halfWayImage);
}
return image;
}

But still my problem is same i m drawing on video i cant get video's screenshot with drawing overlay,so for that i ve to use merging of images.

Thanks :)

UISlider highlight state with different thumb width than normal

10 votes

I'm trying to implement a custom UISlider (subclass of UISlider), that behaves in a similar way to the native slider that has a glow around the thumb when it's highlighted. I'm having trouble with this, though.

The (effective) width of the highlighted thumb is obviously greater than the normal thumb (due to the glow). If I add transparent pixel padding to the normal state image, so that both images have the same width, the issue is that the normal state thumb never looks like it reaches the end of the track (it does reach the end, but the padding makes it appear otherwise).

If I use thumbRectForBounds: to offset the thumb to line up correctly with the beginning of the track, it only makes the issue worse at the other end.

If I keep both images only as wide as they need to be (ie, no padding on the normal state, and the two are not the same width), I've gotten closer. I can set the offset independently in thumbRectForBounds: based on the UIControl.state, but it seems like the there's some math magic going on behind the scenes. The only place where the UISlider thinks the images for both states line up perfectly is the exact center.

It seems like I may need to implement some math that determines the offset of the highlight state based on it relative position along the track. It would need an y-offset of zero at the center (the UISlider would center both images, which means they align). At the extremes, it would need a y-offset that completely makes up for the glow. And in between it would need to interpolate the y-offset.

This seems like a lot of work to recreate something the native slider does though, so perhaps I'm missing something obvious.

Update Current solution:

It's not entirely portable, since it makes some assumptions about the size of the glow being added. I'm adding the glow with an image rather than drawing it directly to the CALayer. I haven't tested how performant this is yet.

Essentially I create a layer that's a square whose dimensions are the height of the default state thumb image, center it over the thumb, and then draw the glow (only the glow, not a separate image of a thumb with a glow, as would be done with a hightlight state image) into the layer.

- (CGRect)thumbRectForBounds:(CGRect)bounds trackRect:(CGRect)rect value:(float)value {
  CGRect r = [super thumbRectForBounds:bounds trackRect:rect value:value];

  [thumbHighlightOverlayLayer removeFromSuperlayer];
  thumbHighlightOverlayLayer = [CALayer layer]; 

  int x = r.origin.x + (r.size.width / 2) - (r.size.height / 2);
  thumbHighlightOverlayLayer.frame = CGRectMake(x, r.origin.y, r.size.height, r.size.height);

  UIImage* thumbHighlightOverlayImage = [UIImage imageNamed:@"thumb-highlight"];
  thumbHighlightOverlayLayer.contents = (id)thumbHighlightOverlayImage.CGImage;

  switch (self.state) {
    case UIControlStateHighlighted:
      [[self layer] addSublayer:thumbHighlightOverlayLayer];
      break;
    default:
      break;
  }

  return r;
}

instead of adding glow effect in the image, it may be better to add it dynamically. you can use CALayer to add glow effect.

CALayer

How to create video from its frames iPhone

10 votes

I had done R&D and got success in how to get frames in terms of images from video file played in MPMoviePlayerController.

Got all frames from this code, and save all images in one Array.

for(int i= 1; i <= moviePlayerController.duration; i++)
{
    UIImage *img = [moviePlayerController thumbnailImageAtTime:i timeOption:MPMovieTimeOptionNearestKeyFrame];
    [arrImages addObject:img];
}

Now the question is that, After change some image file, like adding emoticons to the images and also adding filters, such as; movie real, black and white, How can we create video again and store the same video in Document directory with the same frame rate and without losing quality of video.

After changing some images I had done following code to save that video again.

- (void) writeImagesAsMovie:(NSString*)path 
{
    NSError *error  = nil;
    UIImage *first = [arrImages objectAtIndex:0];
    CGSize frameSize = first.size;
    AVAssetWriter *videoWriter = [[AVAssetWriter alloc] initWithURL:
                                  [NSURL fileURLWithPath:path] fileType:AVFileTypeQuickTimeMovie
                                                              error:&error];
    NSParameterAssert(videoWriter);

    NSDictionary *videoSettings = [NSDictionary dictionaryWithObjectsAndKeys:
                                   AVVideoCodecH264, AVVideoCodecKey,
                                   [NSNumber numberWithInt:640], AVVideoWidthKey,
                                   [NSNumber numberWithInt:480], AVVideoHeightKey,
                                   nil];
    AVAssetWriterInput* writerInput = [[AVAssetWriterInput
                                        assetWriterInputWithMediaType:AVMediaTypeVideo
                                        outputSettings:videoSettings] retain];

    AVAssetWriterInputPixelBufferAdaptor *adaptor = [AVAssetWriterInputPixelBufferAdaptor
                                                     assetWriterInputPixelBufferAdaptorWithAssetWriterInput:writerInput
                                                     sourcePixelBufferAttributes:nil];

    NSParameterAssert(writerInput);
    NSParameterAssert([videoWriter canAddInput:writerInput]);
    [videoWriter addInput:writerInput];

    [videoWriter startWriting];
    [videoWriter startSessionAtSourceTime:kCMTimeZero];

    int frameCount = 0;
    CVPixelBufferRef buffer = NULL;
    for(UIImage *img in arrImages)
    {
        buffer = [self newPixelBufferFromCGImage:[img CGImage] andFrameSize:frameSize]; 

            if (adaptor.assetWriterInput.readyForMoreMediaData) 
            {
                CMTime frameTime = CMTimeMake(frameCount,(int32_t) kRecordingFPS);
                [adaptor appendPixelBuffer:buffer withPresentationTime:frameTime];

                if(buffer)
                    CVBufferRelease(buffer);
            }
        frameCount++;
    } 

     [writerInput markAsFinished];
     [videoWriter finishWriting];
}


- (CVPixelBufferRef) newPixelBufferFromCGImage: (CGImageRef) image andFrameSize:(CGSize)frameSize
{
    NSDictionary *options = [NSDictionary dictionaryWithObjectsAndKeys:
                             [NSNumber numberWithBool:YES], kCVPixelBufferCGImageCompatibilityKey,
                             [NSNumber numberWithBool:YES], kCVPixelBufferCGBitmapContextCompatibilityKey,
                             nil];
    CVPixelBufferRef pxbuffer = NULL;
    CVReturn status = CVPixelBufferCreate(kCFAllocatorDefault, frameSize.width,
                                          frameSize.height, kCVPixelFormatType_32ARGB, (CFDictionaryRef) options, 
                                          &pxbuffer);
    NSParameterAssert(status == kCVReturnSuccess && pxbuffer != NULL);

    CVPixelBufferLockBaseAddress(pxbuffer, 0);
    void *pxdata = CVPixelBufferGetBaseAddress(pxbuffer);
    NSParameterAssert(pxdata != NULL);

    CGColorSpaceRef rgbColorSpace = CGColorSpaceCreateDeviceRGB();
    CGContextRef context = CGBitmapContextCreate(pxdata, frameSize.width,
                                                 frameSize.height, 8, 4*frameSize.width, rgbColorSpace, 
                                                 kCGImageAlphaNoneSkipFirst);
    NSParameterAssert(context);
    CGContextConcatCTM(context, CGAffineTransformMakeRotation(0));
    CGContextDrawImage(context, CGRectMake(0, 0, CGImageGetWidth(image), 
                                           CGImageGetHeight(image)), image);
    CGColorSpaceRelease(rgbColorSpace);
    CGContextRelease(context);

    CVPixelBufferUnlockBaseAddress(pxbuffer, 0);

    return pxbuffer;
}

I am new in this topic so please help me solve this question?

Thanks in advance.

Regards,
Marvin.

You can refer following links hope you get some help :-

  1. http://www.iphonedevsdk.com/forum/iphone-sdk-development-advanced-discussion/77999-make-video-nsarray-uiimages.html

  2. Using FFMPEG library with iPhone SDK for video encoding

  3. Iphone SDK,Create a Video from UIImage

  4. iOS Video Editing - Is it possible to merge (side by side not one after other) two video files into one using iOS 4 AVFoundation classes?

Setting a custom design size for a UITabViewController (in Storyboard)

9 votes

I want to modify an app that currently has a UITabBarController as its initial view controller.

The goal is to have a custom status bar in the top area of the screen that will always be shown no matter which tab is selected. The current UITabBarController may not use the full height of the screen:

/----------------------------\
|Custom Status bar (50 px)   |
|                            |
|----------------------------|
|                            |
|----------------------------| ---
|                            |  |
|                            |  |
|View of the selected tab    |  |
|                            |  |
|                            |  |
|                            |  |
|                            |  | 
|                            |  smaller height of the UITabBarController
|                            |  |
|----------------------------|  |
|Tab bar                     |  |
|                            |  |
\----------------------------/ ---

I use storyboards. I cannot set a (design) size in the Size Inspector window even with simulated metrics size set to 'freeform'.

You can set a UITabBar's this programmatically like so:

UITabBar *myTabBar = [[UITabBar alloc] initWithFrame:CGRectMake(0, 0, 320, 50)];

And then add it to your view, like so:

[MyView addSubview:myTabBar];

You should see Apples UITabBar Class Reference for setting up a UITabBar programmatically.

NSString by removing the initial zeros?

9 votes

How can I remove leading zeros from an NSString?

e.g. I have:

NSString *myString;

with values such as @"0002060", @"00236" and @"21456".

I want to remove any leading zeros if they occur:

e.g. Convert the previous to @"2060", @"236" and @"21456".

Thanks.

NSString *str = @"000123";      
NSString *clean = [NSString stringWithFormat:@"%d", [str intValue]];

ALAssetsLibrary - crash after receiving ALAssetsLibraryChangedNotification

9 votes

Part of my app has a photo browser, somewhat similar to Apple's Photos app, with an initial view controller to browse photo thumbnails and a detail view that's shown when you tap on a photo.

I'm using ALAssetsLibrary to access photos, and I pass an array of ALAsset URL's to my detail view controller so you can swipe from one photo to the next.

Everything works great, until I receive an ALAssetsLibraryChangedNotification while swiping from one photo to another (in the detail view controller), which often results in a crash:

NOTIFICATION: the asset library changed // my own NSLog for when the notification occurs

loading assets... // my own NSLog for when I start reloading assets in the thumbnail browser

Assertion failed: (size == bytesRead), function -[ALAssetRepresentation _imageData], file /SourceCache/AssetsLibrary/MobileSlideShow-1373.58.1/Sources/ALAssetRepresentation.m, line 224.

The specific line of code it crashes on, is in calling [currentRep metadata] as shown here:

- (void)someMethod {
        NSURL *assetURL = [self.assetURLsArray objectAtIndex:index];
        ALAsset *currentAsset;

        [self.assetsLibrary assetForURL:assetURL resultBlock:^(ALAsset *asset) {

            [self performSelectorInBackground:@selector(configureDetailViewForAsset:) withObject:asset];

            } failureBlock:^(NSError *error) {
                    NSLog(@"failed to retrieve asset: %@", error);
        }];
}

- (void)configureDetailViewForAsset:(ALAsset *)currentAsset {
    ALAssetRepresentation *currentRep = [currentAsset defaultRepresentation];

    if (currentAsset != nil) {
        // do some stuff
    }
    else {
        NSLog(@"ERROR: currentAsset is nil");
    }

    NSDictionary *metaDictionary;
    if (currentRep != nil) {
        metaDictionary = [currentRep metadata];

        // do some other stuff
    }
    else {
        NSLog(@"ERROR: currentRep is nil");
    }
}

I understand that once a notification is received, it invalidates any references to ALAsset and ALAssetRepresentation objects... but how am I supposed to deal with the situation where it invalidates something right in the middle of trying to access it?

I've tried setting a BOOL, right when receiving the notification to completely abort and prevent [currentRep metadata] from ever being called, but even that doesn't catch it every time:

if (self.receivedLibraryChangeNotification) {
    NSLog(@"received library change notification, need to abort");
}
else {
    metaDictionary = [currentRep metadata];
}

Is there anything I can do? At this point I'm almost ready to give up on using the ALAssetsLibrary framework.

(note this unresolved thread on the Apple dev forums describing the same issue: https://devforums.apple.com/message/604430 )

It seems the problem is around here:

[self.assetsLibrary assetForURL:nextURL 

    resultBlock:^(ALAsset *asset) {
        // You should do some stuff with asset at this scope
        ALAssetRepresentation *currentRep = [asset defaultRepresentation];
        // Assume we have a property for that
        self.assetRepresentationMetadata = [currentRep metadata];
        ...
        // assume we have a method for that
        [self updateAssetDetailsView];
    } 

    failureBlock:^(NSError *error) {
        NSLog(@"failed to retrieve asset: %@", error);
    }];

Once you have got user asset it is better to copy asset information by providing necessary data to your details controller subviews or by caching for later use. It can be helpful for avoiding ALAsset invalidation troubles. When notification ALAssetsLibraryChangedNotification sent you may need to discard details controller and query the Library content from the beginning.

Performance test tool for iPhone application

9 votes

I am looking for free tool which can help conduction performance test of iPhone application. Is any one familiar with such tool to monitor the iPhone app performance?

Instruments (which is included in Xcode IDE) already provides a good suite of profiling and performance tools:

  • allocations of objects, and mark heap capability to see how your heap grows
  • time profiler that samples all the processes and helps you finding bottlenecks
  • system trace to see how processes inside the applications are scheduled and executed
  • energy diagnostics which helps profiling energy consumption of various devices used by your application

I don't know which kind of performance metrics you need to profile but as usually the good old sentence

95% of the CPU time is spent in 5% of the code

is true even for iOS applications so by profiling with time profiler you will mostly solve any performance issue. Just make sure to study its characteristics a little bit (eg. reverse call stack / objc only etc)

How to send files to other iPhones via Bluetooth

8 votes

I'm doing a little app to allow users to edit and share text fast on the iPhone.

So I know a little of Bluetooth programing for iPhone, but I'm not able to do what I want to do:

  • The text of the app is saved in NSUserDefaults. I want to send this to another iOS device by the key: "Text1", "Text2" or "Text3"( I know that I have to convert the text that will be in a string to NSData, and tren I would like to have it in a NSMutableDictionary with its key)

  • I also want to be looking for new iOS devices arround all the time.

Please help me because I don't know how I can do it and it's so hard to find tutorials of iPhone Bluetooth programming, thank you!

Use GameKit, there are many tutorials.

Use this to find other devices:

GKPeerPickerController *picker = [[GKPeerPickerController alloc] init];
picker.delegate = self;
picker.connectionTypesMask = GKPeerPickerConnectionTypeNearby;
[picker show];

How to transport NSManagedObject subclass between classes?

8 votes

We have made a repository layer for interacting with Core Data that have methods such as allItems(), addItem:(Item*)item where item being the NSManagedObject subclass. When we need to save an item we invoke the method on the repository passing the subclass instance as an argument. However, that does not work because we can't use the initinitializer and the context is hidden inside the repository.

What is the best way to transfer objects when you have an architecture like this? Is making a ItemDTO an passing that around an option? Or are there better ways to solve this such as not using subclassed NSManagedObject at all and just use key/value that works.

I wrotecopy-pasted a sample project that hides the context from model custom classes: branch 10583736.

(it's not final production code, just a quick example, don't expect it to deal with multithreading or weird errors)

Hiding the context to custom classes is just a matter of defining custom methods to deal with every situation where you normally will request the context and use it.

You can define a class for the store layer without exposing the context:

@interface DataStore : NSObject

+ (id)shared;

- (void)saveAll;
- (NSEntityDescription *)entityNamed:(NSString *)name;
/* more custom methods ... */
- (NSManagedObject *)fetchEntity:(NSEntityDescription *)entity withPredicate:(NSPredicate *)predicate;

@end

I suggest to use a common ancestor for all your custom model classes to save some typing. This class can be the only one that interacts with DataStore directly. It doesn't have access to the context.

@interface DataObject : NSManagedObject

+ (NSString *)entityName;
+ (NSEntityDescription *)entity;
- (void)save;
/* more custom methods ... */

@end

Finally your model custom classes defines any method you need probably taking advantage of whatever is provided by the superclass:

@interface Card : DataObject

@property (nonatomic, retain) NSString * question;
@property (nonatomic, retain) NSString * answer;
@property (nonatomic, retain) Deck *deck;

/* return a new card */
+ (Card *)card; 

/* more custom methods ... */

@end

The master branch has a more usual approach where model classes obtain the context and work with it.

How to do 'serial' animation with GCD?

8 votes

I'm trying to make a custom UIView displays on screen for 5s when a remote notification comes.

Code like this:

//customView.alpha = 1.0 here
[UIView animateWithDuration:1 animations:^{
                                  customView.alpha = 0.3;
                              } 
                              completion:^(BOOL finished){
                                  // remove customView from super view.
                              }];

Problem and What I Need

But there're cases that a couple of notification may come at short time interval, in which several customView may be animating at the same time and one may cover others.

I want these animations perform one after another, so that they won't conflict.

Assumed but Failed

//(dispatch_queue_t)queue was created in other parts of the code
dispatch_sync(queue, ^{
    [UIView animationWithDuration:animations:...];
});

After making the animation in GCD queue, I got the same result as the origin code I used, which didn't use GCD. Animations are still conflicting.

BTW, I heard that animations or tasks involving UI should always be run on main thread, but in my second code the animation seemed done smoothy. Why?

If it's the same animation that runs every time then you could just have store the number of times that the animation should run (not the same as the repeat count property of the animation).

When you receive the remote notification you increment the counter and call the method that animates if the counter is exactly one. Then in the methodThatAnimates you recursively call yourself in the completion block while decreasing the counter every time. It would look something like this (with pseudocode method names):

- (void)methodThatIsRunWhenTheNotificationIsReceived {
    // Do other stuff here I assume...
    self.numberOfTimesToRunAnimation = self.numberOfTimesToRunAnimation + 1;
    if ([self.numberOfTimesToRunAnimation == 1]) {
        [self methodThatAnimates];
    }
}

- (void)methodThatAnimates {
    if (self.numberOfTimesToRunAnimation > 0) {
        // Animation preparations ...
        [UIView animateWithDuration:1 
                         animations:^{
                                  customView.alpha = 0.3;
                         } 
                         completion:^(BOOL finished){
                                  // Animation clean up ...
                                  self.numberOfTimesToRunAnimation = self.numberOfTimesToRunAnimation - 1;
                                  [self methodThatAnimates];
                         }];
    }
}