1

I need to create one View or ImageView, which can be remotely updated from a computer without major App Store Update. So basically, it needs to be able to be changeable through the internet browser or command line tool. So for example today I can have one picture, and in some days i can remotely change it. Is there code I need to implement or is there a service that can help me in that? Thanks a lot folks!

That's the code so far:

#import "ViewController.h"

 @interface ViewController ()
 @property (strong, nonatomic) IBOutlet UIImageView *imageView;

 @end

 @implementation ViewController



 - (void) viewDidLoad
 {
     [super viewDidLoad];
     //do stuff here
     if(&UIApplicationWillEnterForegroundNotification) { //needed to run on older devices,  otherwise you'll get EXC_BAD_ACCESS
         NSNotificationCenter *notificationCenter = [NSNotificationCenter defaultCenter];
         [notificationCenter addObserver:self selector:@selector(enteredForeground:)  name:UIApplicationWillEnterForegroundNotification object:nil];
     }


 }
 - (void)enteredForeground:(NSNotification*) not
{
    UIImageView *imageView; // Assumed to already be setup in a view controller
    PFQuery *query = [PFQuery queryWithClassName:@"Image"];
    [query getObjectInBackgroundWithId:@"nMW24stvhT" block:^(PFObject *imageObject, NSError *error) {

        if (!error) {
            PFFile *imageFile = imageObject[@"image"];
            [imageFile getDataInBackgroundWithBlock:^(NSData *data, NSError *error) {
                if (!error && data) {
                    UIImage *image = [UIImage imageWithData:data];
                    if (image) {
                        imageView.image = image;
                    }
                }
            }];
        }
    }];}

    - (void)didReceiveMemoryWarning
 {
 [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
 }

 @end
  • 2
    This question is a bit broad but basically you host the images/files on a server and your app looks for updated files once in a while. When an updated file is found, the app downloads the file and shows the new one to the user. – rmaddy Apr 18 '14 at 17:51

2 Answers2

1

I'd use something like Parse, and have a record with an image in it. Then in the application you can just use the Parse SDK to fetch that image each time that screen is shown. You could also use Parses push notifications to tell the the user that a new image exists, and if you want to be really fancy use iOS 7 new slient pushes to fetch the new image in the background so the user doesn't even see it loading!

The other option would be to host an image somewhere, and then use a image fetching category (AFNetworking or SDWebImage both have one) to again update the image when the screen is shown.

As its just one image, you might be better off hosting it somewhere - I suppose it depends on the amount of effort you want to put in to it :)

Some example code if you host it yourself and use AFNetworking:

UIImageView *imageView; // Assumed to already be setup in a view controller
[imageView setImageWithURL:[NSURL URLWithString:@"http://hostname.com/path/to/your/image.png"]];

And with Parse

UIImageView *imageView; // Assumed to already be setup in a view controller
PFQuery *query = [PFQuery queryWithClassName:@"Image"];
[query getObjectInBackgroundWithId:@"OBJECT ID HERE" block:^(PFObject *imageObject, NSError *error) {

     if (imageObject) {
          PFFile *imageFile = imageObject[@"image"];
          [imageFile getDataInBackgroundWithBlock:^(NSData *data, NSError *error) {
              if (data) {
                  UIImage *image = [UIImage imageWithData:data];
                  if (image) {
                      imageView.image = image;
                  }
              } else {
                  NSLog(@"Error fetching image file: %@", error);
              }
          }];
     } else {
          NSLog(@"Error fetching object: %@", error);
     }
 }];

Then in the Parse data browser you want to add this sort of thing: Setup

Which is basically, create a new custom class called Image. Add another column to this class called image of type File.

Then add a file and you'll automatically get a objectId created for you (which you'd need for the above code example): Added image

Updated with your code:

#import "ViewController.h"

 @interface ViewController ()
 @property (strong, nonatomic) IBOutlet UIImageView *imageView;

 @end

 @implementation ViewController

 -(void)dealloc
 {
     [[NSNotificationCenter defaultCenter] removeObserver:self];
 }

 - (void) viewDidLoad
 {
     [super viewDidLoad];
     //do stuff here
     NSNotificationCenter *notificationCenter = [NSNotificationCenter defaultCenter];
     [notificationCenter addObserver:self selector:@selector(enteredForeground:)  name:UIApplicationWillEnterForegroundNotification object:nil];   
 }

 -(void)viewWillAppear:(BOOL)animated
 {
     [super viewWillAppear:animated];

     [self updateImage];
 }

 - (void)enteredForeground:(NSNotification*) not
 {
     [self updateImage];
 }

 -(void)updateImage
 {

    PFQuery *query = [PFQuery queryWithClassName:@"Image"];
    [query getObjectInBackgroundWithId:@"nMW24stvhT" block:^(PFObject *imageObject, NSError *error) {

        if (imageObject) {
            PFFile *imageFile = imageObject[@"image"];
            [imageFile getDataInBackgroundWithBlock:^(NSData *data, NSError *error) {
                if (data) {
                    UIImage *image = [UIImage imageWithData:data];
                    if (image) {
                        self.imageView.image = image;
                    }
                } else {
                    NSLog(@"Error fetching image file: %@", error);
                }
            }];
        } else {
          NSLog(@"Error fetching object: %@", error);
        }
    }];
}


@end
Rich
  • 8,108
  • 5
  • 46
  • 59
  • How would I do that with parse or with the host... I'm totally new to ios and need help...what would you recommend? – user3549694 Apr 18 '14 at 17:58
  • Hey! Could you please give me some sample code? Thanks! – user3549694 Apr 18 '14 at 18:05
  • You would create a Parse account and then use the SDK (which you can add with [Cocoapodss](http://guides.cocoapods.org)) to connect to Parse and fetch the image. – Rich Apr 18 '14 at 18:06
  • @user3549694 there's a good [guide](https://parse.com/docs/ios_guide#files-images/iOS) in the Parse documentation. The Parse getting started guide is also pretty good. – Rich Apr 18 '14 at 18:09
  • how do I fetch the image? – user3549694 Apr 18 '14 at 18:10
  • Have you just read that link I put in my above comment? – Rich Apr 18 '14 at 18:11
  • yes, i just now did! thanks! But could i ask where i uplod the new Photo to? – user3549694 Apr 18 '14 at 18:14
  • You'd have to sign up for a Parse account – Rich Apr 18 '14 at 18:15
  • and then do what? I have a parse account and i will download the sdk. Then i will include one Picture, covert it to data and then? Where do i upload the next immage???? – user3549694 Apr 18 '14 at 18:17
  • I'll add a screen shot - hang on. – Rich Apr 18 '14 at 18:22
  • @user3549694 there we go, all that should get you on your way – Rich Apr 18 '14 at 18:27
  • ok!!! and where does the picture have to be hosted? Can it be on for example facebook? – user3549694 Apr 18 '14 at 18:28
  • As it says in the screen shot `Upload File` - Parse hosts the image, you just click on that button and then select an image from your computer – Rich Apr 18 '14 at 18:29
  • OMG! YOU ARE AMAZING THANKS SOOOOO MUCH!!! I'LL GO AND TRY IT RIGHT NOW! CAN I ASK for your e-mail if i need anything else? – user3549694 Apr 18 '14 at 18:31
  • Oh, but how can i change it? That for example today i have one Image and in 2 days i need another one? If i raplace that immage, will it have the same obejct id? @Rich – user3549694 Apr 18 '14 at 18:35
  • @user3549694 just delete the current image (right click on it in the data browser and `Delete value`) and then upload another one. As long as the ID doesn't change it'll work. – Rich Apr 18 '14 at 18:37
  • If you do accidentally change the `ID`, just edit it back to what it originally was - you'll have that saved in your code if you forget it. – Rich Apr 18 '14 at 18:38
  • ok... and how often will the app check for the new image? And what happens if there's no internet? Will the old image stay in? – user3549694 Apr 18 '14 at 18:39
  • Up to you. I'd have the view controller that owns the `imageView` to update the image in `viewWillAppear:`. You could also listen for `UIApplicationWillEnterForegroundNotification` in that view controller and update the image when that happens to. – Rich Apr 18 '14 at 18:41
  • And the internet thing? – user3549694 Apr 18 '14 at 18:42
  • OH, AND HOW DO I O THAT WITH UIAPLICATION... DO I JUST PASTE THE CODE IN THERE? – user3549694 Apr 18 '14 at 18:42
  • If there is no internet the code will not run (`if (!error)`). I'll add another `if` in case there is no image. – Rich Apr 18 '14 at 18:43
  • THANKS! COULD YOU DO SO, THAT THE LAST IMAGE WILL STAY THERE? THANKS – user3549694 Apr 18 '14 at 18:45
  • Already done it - the second `if(!error && data)` has changed and one inside of that added. And see [this](http://stackoverflow.com/questions/3535907/how-to-tell-when-controller-has-resumed-from-background) answer for the `UIApplicationWillEnterForegroundNotification`. – Rich Apr 18 '14 at 18:46
  • Ok! There's one small problem... It says expected expression after rthe little last bit of code... after the }]; Why and what to do? – user3549694 Apr 18 '14 at 18:52
  • @user3549694 you really could have worked that one out I'd hope! But I've fixed it the answer for the benefit of others. I had too many `{` – Rich Apr 18 '14 at 18:54
  • I need more help... It gave me like 10 errors with this `code:Undefined symbols for architecture i386: "_SCNetworkReachabilityCreateWithName", referenced from: +[PFInternalUtils(Reachability) isParseReachable] in Parse(PFInternalUtils.o) -[PFCommandCache init] in Parse(PFCommandCache.o) "_SCNetworkReachabilityGetFlags", referenced from: +[PFInternalUtils(Reachability) isParseReachable] in Parse(PFInternalUtils.o) ___22-[PFCommandCache init]_block_invoke inParse(PFCommandCache.o)` – user3549694 Apr 18 '14 at 18:58
  • You really need to start to look around, I googled the first line of that error and this was the second result http://stackoverflow.com/a/18319944/849645 You need to read the [getting started guide](https://parse.com/apps/quickstart) this has all this information in it. – Rich Apr 18 '14 at 19:01
  • Ok! Now it builds... but it doesn't load any image... – user3549694 Apr 18 '14 at 19:06
  • I've set everything up as it was suposed to be. A custom Class called image, a new row. I copied the exact code and pasted it under here: `- (void) viewDidLoad { if(&UIApplicationWillEnterForegroundNotification) { //needed to run on older devices, otherwise you'll get EXC_BAD_ACCESS NSNotificationCenter *notificationCenter = [NSNotificationCenter defaultCenter]; [notificationCenter addObserver:self selector:@selector(enteredForeground:) name:UIApplicationWillEnterForegroundNotification object:nil]; } }` – user3549694 Apr 18 '14 at 19:14
  • `- (void)enteredForeground:(NSNotification*) not {UIImageView *imageView; // Assumed to already be setup in a view controller PFQuery *query = [PFQuery queryWithClassName:@"Image"]; [query getObjectInBackgroundWithId:@"nMW24stvhT" block:^(PFObject *imageObject, NSError *error) { if (!error) { PFFile *imageFile = imageObject[@"image"]; [imageFile getDataInBackgroundWithBlock:^(NSData *data, NSError *error) { if (!error && data) { UIImage *image = [UIImage imageWithData:data]; if (image) { imageView.image = image; } } }]; } }];}` – user3549694 Apr 18 '14 at 19:14
  • You'd need to add `[self enteredForeground:nil]` into `viewWillAppear:` too (Also you don't need the `if(&UIApplicationWillEnterForegroundNotification)` either unless you're going back as far as iOS 4) – Rich Apr 18 '14 at 19:16
  • Can i please zip up the project and send it to you for you to take a closer look? bacause i can't find the `viewWillAppear:` – user3549694 Apr 18 '14 at 19:24
  • what's your E-Mail @Rick – user3549694 Apr 18 '14 at 19:25
  • I'm not here to debug your code! You override the method on your view controller. Update your question with your code you've got so far. – Rich Apr 18 '14 at 19:26
  • @Rick ok... I did and on parse i did the exact same thing as you did! – user3549694 Apr 18 '14 at 19:35
  • @user3549694 I've updated my answer, I've split out the notification method so keep it cleaner. I've also added the missing `dealloc` method - you really need to read and understand the answers, instead of blindly using them :( – Rich Apr 18 '14 at 19:38
  • ok... I'm sorry... I will try to undersantd... now i get this thing all the time: `2014-04-18 21:40:26.936 TEST[18936:60b] *** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'You have to call setApplicationId:clientKey: on Parse to configure Parse.' *** First throw call stack:` How can i solve it and the second things is... Now if there is no internet, will the last downloaded be displayed? Thanks – user3549694 Apr 18 '14 at 19:42
  • I've also just updated the error checking code to aid in debugging (see the `NSLog`s). And I noticed you weren't setting `imageView` to the correct property. – Rich Apr 18 '14 at 19:42
  • You **need to read the getting started guide** for Parse. You *clearly* have not read it. – Rich Apr 18 '14 at 19:43
  • Thank you! Thank you Rich! I just read the QuickStart and everything works perfectly! I have one more question... The last one just to make sure i understood correctly... What happens if there's no internet and the app is launched? Thanks again! – user3549694 Apr 18 '14 at 19:50
  • Try it. You'll get the first `NSLog` reporting an error. I believe from a quick [look](https://www.parse.com/questions/pffilecache-refresh-and-pffile-versioning) that the `PFFile`s are cached. So as long as they've downloaded the image once it will show. Best way is to try it yourself. – Rich Apr 18 '14 at 19:54
  • OK!!! THANKS FOR EVERYTHING! I WILL TRY IT OUT AND THEN EITHER COMMENT OR ACCEPT! STAY TUNES PLAESE!! THANKS! YOU"RE AMAZING! – user3549694 Apr 18 '14 at 19:57
  • ok... I tried... It does't.. It says try again after x seconds... but there's no image... What can i do? – user3549694 Apr 18 '14 at 20:00
  • Actally... It's fine... I bothered you too much already... So thank you! Thank you Very much rich! Bless you and happy easter! – user3549694 Apr 18 '14 at 20:07
0

You could have your app check in with a server at regular intervals (or respond to a push notification, depending on your needs and resources). Then it could download an image based on a URL file that you update on a server somewhere.

Alternatively, you could make your app respond to special URL schemes (myApp://), and make links on Web pages that, when tapped, will cause your app to open and perform some action. You can learn more about custom URL schemes here.

Zev Eisenberg
  • 8,080
  • 5
  • 38
  • 82
  • how would it work with push notifications? – user3549694 Apr 18 '14 at 17:57
  • The notification would basically be an instruction for the app to check a server and download new content. – Zev Eisenberg Apr 18 '14 at 17:58
  • Could you either show me sample code or tell me how to write some please? Oh and if i don't have a server, which hosting service to chose? – user3549694 Apr 18 '14 at 17:59
  • Sorry, I’ve never used push notifications. But once the app is running, you can use AFNetworking or SDWebImage as in [Rich’s answer](http://stackoverflow.com/a/23159432/255489) to fetch the image. – Zev Eisenberg Apr 18 '14 at 18:03
  • ok, but how would the code look like? Just for checking every some minutes? – user3549694 Apr 18 '14 at 18:05
  • You would probably kick it off in `application:didFinishLaunchingWithOptions:` or in the `-viewDidLoad` of some view controller. If the app will be long-running, use a timer to re-check the server every _n_ minutes. – Zev Eisenberg Apr 18 '14 at 18:07
  • Yes... That's what i mean... what code should it have in the `viewDidLoad`? – user3549694 Apr 18 '14 at 18:08
  • If you have a `@property` of an `NSTimer`, init the timer and set it to call some method at some time interval (for example, but that’s just one way to do it). – Zev Eisenberg Apr 18 '14 at 18:12
  • You would make a method called something like `- (void)checkForImage`. Put your network checking code in there. – Zev Eisenberg Apr 18 '14 at 18:25
  • @ZevEisenberg you know that feeling when sometimes you wish you hadn't checked SO...! – Rich Apr 18 '14 at 18:31