Show Menu

Looking to hire an app developer?

Submit your 30 day Job Listing for FREE

Welcome to the second part of this tutorial.

Previous in the series:
How to make a magazine app in iOS – Part I

[socialRansom link=”https://github.com/viggiosoft/HowToMakeAMagazineApp/archive/master.zip”]

The iOS5 revolution

A lot of water has flowed under the bridge since our first part of this tutorial. We’re sorry for the delay, but at the time of writing we were aware of the new featured introduced with iOS5 but we were still under NDA and not authorized to disclose anything about the SDK. Finally we’re now able to provide our example magazine app with the double iOS4/iOS5 compatibility.

iOS Newsstand icon

I will not spend my time explaining all the Newsstand features, all in all we’re creating a magazine app here and the Newsstand implementation details go beyond our original purposes. I have written a two parts tutorial in my personal blog that you can read here and here, and that covers all Newsstand aspects and the required (by Apple reviewers) subscriptions. In short, Newsstand is both a new way to present magazines in the iPad and iPhones, where the original icon is replaced by a cover of the magazine or newspaper and is placed under a special group dedicated to collect all Newsstand icons installed by the user. For the developer it is also a framework, called Newsstand Kit, that introduces a new methodology to organize, download and install the app content.

The example app

The screenshot shows the final appearance of the app. A set of nine magazines with their nine fruity cover. You can download a magazine, see the progress bar change while the operation is in progress and finally read it. The other screenshot shows the appearance in the Newsstand. The typical icon has been replaced by a magazine-like representation inside the Newsstand group. The same, if run on an iPad with iOS4 installed will show the classical icon instead.

The full app code is available on GitHub. Don’t consider it as a production code, so please don’t try to reuse as it is with your clients unless you have tested it in all possible corner cases. Anyway it can be considered as a valid starting point for real apps. Essentially the principles behind the code architecture have been depicted in Part I of this tutorial; if you haven’t read it yet I recommend to jump to that article before entering in this one, at least to understand the key components of such an app. The driving aim is to keep the issues management (controller, don’t confuse it with “view controller”) separated as much as possible from the UI concerns. This means that in theory the whole code behind the Store Manager and Issue Models part can be reused even in a Mac OSX app, as they relationship with UI stuff is minimum.

I have setup this app using the basic single window Xcode template and then added the two main components in the application delegate startup method:


- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{    
    // here we create the "Store" instance
    _store = [[Store alloc] init];
    [_store startup];

    self.shelf = [[[ShelfViewController alloc] initWithNibName:nil bundle:nil] autorelease];
    _shelf.store=_store;

    self.window = [[[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]] autorelease];
    self.window.rootViewController = _shelf;
    [self.window makeKeyAndVisible];
    return YES;
}

The two components are:

  • the Store class, which represents the Store Manager block in the app architecture; this Class is a subclass of NSObject and is not linked to the user interface.
  • the ShelfViewController represents the UI of the application. It is linked to the store using a specific property. Note that the controller will not access the store exposed properties, but will get the needed information via a simple API. We could have used a delegate pattern instead, but as both blocks are essentially custom blocks in a custom app, there is not much need to define a protocol for their interaction. We can say that the controller part has been split in two parts, one for the UI, the shelf, and one for the back-end, the Store. Their link is such that the Shelf depends on the Store (strict link), not viceversa. Any Store to Shelf communication is done using lazy methods, based on notifications.

The app has then been integrated with the new Newsstand requirements in the info plist. Again have a look at Apple docs or my tutorial for a detailed guide.

Models and Controllers

We have one model in this app, it is the Issue model which represents a single magazine issue in the store or in the user library. There is also one controller, which is the Store. As I said this controller is not a UI component but the app back-end is self sufficient with these two components. In theory we can retrieve the store status and download magazines even without any user interface. This is a basic concept in magazine apps, where many events happen in the background are not related to direct user interaction: this means that the app should be capable to perform several tasks even if the user interface has not been loaded at all.

The role of the Issue class is to represent all relevant magazine properties, that is a unique identifier, a title, a release date, a link to the cover image, obviously the link (URL) to the content (which can be a pdf file, an epub file or a zip file for complex packages). In particular the unique identifier is a piece of data that must be maintained along the full life of the issue: it is the only way to uniquely identify a particular issue, independently of localization issues (e.g. the title can change in different countries, but not the unique ID). Besides it is the link to the Newsstand way to identify issues (the NKIssue‘s name field) and it can be also used to link the product with the App Store if we’re going to implement In App Purchases.

Other than this role, the Issue class will have a central role in the downloading of a magazine. Essentially the Store class will schedule a download but it will be monitored (progress) and then finished (effective magazine installation) by the Issue class.

Finally this class has limited capabilities to represent a magazine already downloaded and available in the user library. For this we provide the simple isIssueAvailableForRead that will be used by the user interface to know which action is possible with an issue (read or download) and eventually display the contents.

The Store class is the app controller. It is initialized at the very beginning of the app and its instance is never released. Besides immediately after initialization this class will fetch the store contents from the publisher server. In the example we decided to implement the store contents as a simple property list, and we instruct the store to retrieve this property list, decode it and create the Issue objects, and finally download their cover images. All this is done asynchronously using the Grand Central Dispatch and at the end a notification will be sent to inform all interested objects (in particular the view controller) that the store contents are ready and the UI can be safely displayed. Note that the store status is represented by a property status. We have overridden its setter method to post a notification that informs any interested observer of the new state. For simplicity we decided to limit the possible statuses to “not initialized”, “downloading”, “ready” and “error”. A more complex app can introduce extra states if needed. Finally as a fallback in case of missing connection (the user must be able to access his/her content even if not connected to the Internet) we reload a locally saved copy of the store.

The central piece of the code is in the downloadStoreIssues method of the class, that we report below:


-(void)downloadStoreIssues {
    self.status=StoreStatusDownloading;
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH,0), ^{
        NSArray *_list = [[NSArray alloc] initWithContentsOfURL:[NSURL URLWithString:@"http://www.viggiosoft.com/media/data/iosblog/magazine/store.plist"]];
        if(!_list) {
            // let's try to retrieve it locally
            _list = [[NSArray alloc] initWithContentsOfURL:[self fileURLOfCachedStoreFile]];
        }
        if(_list) {
            // now creating all issues and storing in the storeIssues array
            [_list enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
                NSDictionary *issueDictionary = (NSDictionary *)obj;
                Issue *anIssue = [[Issue alloc] init];
                anIssue.issueID=[issueDictionary objectForKey:@"ID"];
                anIssue.title=[issueDictionary objectForKey:@"Title"];
                anIssue.releaseDate=[issueDictionary objectForKey:@"Release date"];
                anIssue.coverURL=[issueDictionary objectForKey:@"Cover URL"];
                anIssue.downloadURL=[issueDictionary objectForKey:@"Download URL"];
                anIssue.free=[(NSNumber *)[issueDictionary objectForKey:@"Free"] boolValue];
                [anIssue addInNewsstand];
                [storeIssues addObject:anIssue];
                [anIssue release];
                // dispatch cover loading
                if(![anIssue coverImage]) {
                    dispatch_sync(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
                        NSData *imgData = [NSData dataWithContentsOfURL:[NSURL URLWithString:anIssue.coverURL]];
                        if(imgData) {
                            [imgData writeToURL:[anIssue.contentURL URLByAppendingPathComponent:@"cover.png"] atomically:YES];
                        }
                    });
                }
            }];
            // let's save the file locally
            [_list writeToURL:[self fileURLOfCachedStoreFile] atomically:YES];
            [_list release];
            self.status=StoreStatusReady;
        } else {
            ELog(@"Store download failed.");
            storeIssues = nil;
            self.status=StoreStatusError;
        }
    });
}

Note that in the code above for simplicity I have queued the cover downloading immediately after the property list download. Probably this is not the best way to do this, as we are adding extra networking steps before presenting the app status, with possible delays if network conditions are not good. We can do this in an example where we know that the number of issues is limited, probably in a real app it makes more sense to do this in a background job and then notify the UI to update its status every time a new cover is ready to be displayed.

The view controller

The user interface will wake up immediately, and will change its appearance based on the notifications coming from the store. When the notification center will deliver the store “I’m ready” message to the UI, this one will load all UI issue representations (the CoverView class in the code, a basic view with really minimum application logic) and show the shelf to the user.

At this point the app terminated its back-end processing and is waiting for user commands. Here we have two possibilities:

  • A magazine has been downloaded, the user will see a “READ” button, clicking on it he will be able to read it. In our example all our content is made of pdf files, we decided to use the Quick Look framework in iOS, it is enough for our purposes.
  • A magazine has not been downloaded yet, the user will see a “DOWNLOAD” button, clicking on it the download will start and we’ll show a progress bar. At the end we need to replace the button label and hide the progress. We’ll see this part in more detail.

The view controller is dependent on the store. In order to get the issues information (number of issues, detail of each issue) it will not access directly to the store properties but will use a very simple API, made of three methods:


/* "numberOfIssues" is used to retrieve the number of issues in the store */
-(NSInteger)numberOfStoreIssues;

/* "issueAtIndex:" retrieves the issue at the given index */
-(Issue *)issueAtIndex:(NSInteger)index;

/* "issueWithID:" retrieves the issue with the given ID */
-(Issue *)issueWithID:(NSString *)issueID;

Based on this information, and on the Issue properties, it will create the Issue view representation (CoverView) and place it on the screen.

Downloading a magazine

In a magazine app there are three critical sections: retrieve and display of the store contents, download the contents and finally read them (a good PDF or epub reader is mandatory in an app like that; it’s not the purpose of this tutorial, aimed to explain the architecture and the techniques needed to make such an app, but it is a relevant part in the user experience).

My approach in the magazine download is that the user must be completely free to do any action and such actions shouldn’t interfere with the result of the download. Now many apps take a shortcut: they put a spinner in the center of the screen, then block any user interaction with the UI objects behind the spinner and ask the user to wait. It’s easy to do this, but it is not the better user experience. While waiting the user can read another issue, can navigate inside the store or decide to switch temporarily to another application or finally can temporarily lose the network. Newsstand Kit provides a system level methodology that simplifies (in some cases) the developer life but at the same time removes any excuse on not doing a good job in term of user experience.

As soon as the user triggers a new download, the view controller will send its download request to the store class. In the code below you can see the scheduleDownloadOfIssue: code. This method will prepare the network request and will send it in the background. Note how we split the app behavior based on the operating system version we’re on. If it is iOS5 then we must use the Newsstand approach – where the downloading will be managed by the system in a Newsstand queue – , if we are in iOS4 we’ll follow a classic methodology based on NSOperation: in this case I missed for simplicity to get the content length of the content to be downloaded, so in the iOS4 case the progress bar will not be displayed. This information instead if provided “for free” by Newsstand.


-(void)scheduleDownloadOfIssue:(Issue *)issueToDownload {
    NSString *downloadURL = [issueToDownload downloadURL];
    NSURLRequest *downloadRequest = [NSURLRequest requestWithURL:[NSURL URLWithString:downloadURL]];
    if(isOS5()) {
        // iOS5 : use Newsstand
        NKIssue *nkIssue = [issueToDownload newsstandIssue];
        NKAssetDownload *assetDownload = [nkIssue addAssetWithRequest:downloadRequest];
        [assetDownload downloadWithDelegate:issueToDownload];
    } else {
        // iOS4 : use NSOperation
        NSURLConnection *conn = [NSURLConnection connectionWithRequest:downloadRequest delegate:issueToDownload];
        NSInvocationOperation *op = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(startDownload:) object:conn];
        if(!downloadQueue) {
            downloadQueue = [[NSOperationQueue alloc] init];
            downloadQueue.maxConcurrentOperationCount=1;
        }
        [downloadQueue addOperation:op];
        [downloadQueue setSuspended:NO];
    }
}

// iOS4 only
-(void)startDownload:(id)obj {
    NSURLConnection *conn = (NSURLConnection *)obj;
    [conn start];
}

In the two cases I’d like to emphasize the fact that the Store initiates the download operation but then it will delegate any further processing to the interested part, the is the Issue to be downloaded. So it will be the Issue class that will monitor the download and then will finalize it.

The Issue class will behave as delegate of the download operation triggered by the Store class. The delegate protocol changes if you’re using Newsstand or not. In the former case you will need to be compliant with the NSURLConnectionDownloadDelegate protocol while in the latter the protocol to be respected will be the un-documented (or: documented in the header files only!) NSURLConnectionDataDelegate which is a “spin-off” of the classic NSURLConnectionDelegate. The difference between the two protocols in that one will write in the file system, the other in memory. Again don’t use the “data” approach for production purposes, here we’re loading the whole content in memory and then saving on disk when the content has been completely downloaded: really not the best approach if your content is hundred of megabytes, your app will certainly crash.

In order to visually track the progress and then update the user interface, we decided, being coherent of our principles, to keep the application store controller independent on any UI choice. To do this we make use of KVO and Notifications. Essentially when the view controller starts a download, it will set itself and the magazine view as notification observers of the download result, in order to update its status as soon the download terminates (with success or with error):


-(void)downloadIssue:(Issue *)issue updateCover:(CoverView *)cover {
    cover.progress.alpha=1.0;
    cover.button.alpha=0.0;
    [issue addObserver:cover forKeyPath:@"downloadProgress" options:NSKeyValueObservingOptionNew context:NULL];
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(issueDidEndDownload:) name:ISSUE_END_OF_DOWNLOAD_NOTIFICATION object:issue];
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(issueDidFailDownload:) name:ISSUE_FAILED_DOWNLOAD_NOTIFICATION object:issue];
    [[NSNotificationCenter defaultCenter] addObserver:cover selector:@selector(issueDidEndDownload:) name:ISSUE_END_OF_DOWNLOAD_NOTIFICATION object:issue];
    [[NSNotificationCenter defaultCenter] addObserver:cover selector:@selector(issueDidFailDownload:) name:ISSUE_FAILED_DOWNLOAD_NOTIFICATION object:issue];
    [_store scheduleDownloadOfIssue:issue];
}

Both the cover view and the view controller will need to unregister from the notification center as soon as the download operation terminates. Besides to allow the cover view to keep track of the progress status, as the download starts it will be registered as a KVO observer of the downloadProgress property of the Issue. This means that for each change of this property, that will occur during the downloading phase, the cover view will be informed of the change to update the progress bar (so we have here a separation again of the back-end property, the download progress, from the UI, the UIProgressBar). The cover view will unregister itself as soon as download terminates.

When the download terminates, the Issue instance will copy the downloaded content to the final destination. In the Newsstand framework this destination is specified by the system, in iOS4 will copy it in the Caches directory to be compliant with iCloud requirements (yes, iOS4 doesn’t work with iCloud but our app is the same for both generations of the OS, so we must be good citizens in any case).

In the Newsstand case we’ll also need to update the cover image for the Newsstand icon. We’ll do it with a simple command inside the code that manages the download termination (at the end we also send the end of download notification we mentioned previously):


-(void)connectionDidFinishDownloading:(NSURLConnection *)connection destinationURL:(NSURL *)destinationURL {
    // copy the file to the destination directory
    NSURL *finalURL = [[self contentURL] URLByAppendingPathComponent:@"magazine.pdf"];
    ELog(@"Copying item from %@ to %@",destinationURL,finalURL);
    [[NSFileManager defaultManager] copyItemAtURL:destinationURL toURL:finalURL error:NULL];
    [[NSFileManager defaultManager] removeItemAtURL:destinationURL error:NULL];
    // update Newsstand icon
    [[UIApplication sharedApplication] setNewsstandIconImage:[self coverImage]];
    // post notification
    [self sendEndOfDownloadNotification];
}

Conclusions

This is the conclusion of this tutorial. We decided after a long interval to make an effort to propose a complete app valid for both iOS4 and iOS5 environments. In the code you will find more interesting stuff, e.g. a “hook” to the Store Kit: this is a typical issue not considered by developers when they make applications that sell magazines. In such case storing the issue price in the publisher server is not of help as we must retrieve the pricing information from the only relevant source, that is the App Store. To do this our app must – asynchronously – query the iTunes store for the prices of all the publications and then display them once retrieved. I’m not adding this extra step in the code, just the hook as placeholder for future extensions, but of course if required by our readers I can extend this tutorial further. I would appreciate any suggestion and any contribution in the GitHub hosted code, I would like to see the example code provided with this tutorial as a good skeleton for new apps. If you didn’t enjoy this article, at least you can enjoy the literature classics (and a Django manual…) that I used to create my PDF files.

having issues?

We have a Questions and Answer section where you can ask your iOS Development questions to thousands of iOS Developers.

Ask Question

FREE Download!

Get your FREE Swift 2 Cheat Sheet and quick reference guide PDF download when you sign up to SwiftMonthly


Sharing is caring

If you enjoyed this tutorial, please help us and others by sharing using one of the social media buttons below.


Written by:

Husband, father, electronics engineer and software developer, located in North Italy. I'm in the iOS market since 2008 with now many apps in the store. Co-founder of italian startup i3factory.com and consultant of other software houses in Italy, US and Japan. Twitter: @viggiosoft My motto is: simplicity is the ultimate sophistication.

Comments

There are currently: 48 Responses to “How to make a magazine app in iOS – Part II”. Leave your comment!

Great Explanation, Thank you very much.


in this example, the content is a pdf. if we want to make a full native magazine app, how we can do it? issues will be xib files and classes. each page will be a class



URGENT
Hi, this was very helpful but i wanted to know how i can add a 10th issue. I added a 10th item in store.plist but the 10th item doesnt show when i run the simulator.
thanks


Thanks for such a great tutorial. I really provided me such a learning curve & have modified the UI , kept the content into scrollView and lot more changes.

One more thing, there is one issue while downloading unzip/PDF file from the server.

– (void)connection:(NSURLConnection *)connection didWriteData:(long long)bytesWritten totalBytesWritten:(long long)totalBytesWritten expectedTotalBytes:(long long)expectedTotalBytes;

This is the delegate method which gets called when I use the url to download the content from my server. It works fine when I try to download the Zip file from the server (returns expectedTotalBytes as expected )but the issue lies when I try the same thing with PDF file. (returns expectedTotalBytes as -1). It didn’t get the actual expectedTotalbytes as result the Progress bar doesn’t progress gradually, though the PDF file gets downloaded and reading is also done properly.

What would be reason, I tried to upload several types of PDF files and also tried with changing R/W access of the PDF files on the server.Is there something which I am missing out at the time of implementation. I am really stuck with this point.


We absolutely love your blog and find almost all of your
post’s to be exactly what I’m looking for. Does one offer guest writers to
write content for yourself? I wouldn’t mind producing a post or elaborating on many of the subjects you write concerning here. Again, awesome blog!


The tutorial really helped get my head around the concepts before taking the plunge into the Baker framework. V. superb!


Hi, I make this project with vfr/reader to open Pdf file but I have a problem about this

http://stackoverflow.com/questions/13196337/xcode-with-vfr-reader-loading-pdf-mistake

How can I solve this problem ?

Thank you.


Hi guys!
I would like to make an issue in html so instead of downloading a .pdf document, the store should download a folder and open index.html from it.
How do I change the project to do so?


Hi! I’m trying to add your howtomakeamagazine project into a storyboard tabbar project. I just have a little problem: In my log I can see that there is activity, but the loading view remains and the containerview doesn’t show. I think the problem is in the appDelegate:
” self.window = [[[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]] autorelease];
self.window.rootViewController = _shelf;
[self.window makeKeyAndVisible];”

As i’m no longer using a window-based projet, this must be the problem. Do you have any idea of what I have to do?

Thank you so much!


nice tutorial, thanks for sharing!
one question:
how can we add an erase button (and method) to an issue?


Great job!
Is it in your future plan to make an ARC (automatic reference counting) version of this project?
Thank you for this tutorial…


Great Post!


as I can do to read html instead of PDF? can?


    The approach is exactly the same. Clearly you must replace the “PDF reader” block with an “HTML reader”. You can checkout some of the open source projects dedicated to make magazines and books powered by HTML5, one of them is Baker.


Brilliant Tutorial!
How would you implement this into Storyboards rather than using a xib?? Would this be possible and how easy would it be for a newbie?


Hi! thank you for this awesome tutorial.
I was wondering: with the New iPad released, what do we have to do to have a normal version of our issue and a retina one? Do we have to create a zip file to be extracted and recognized by the store element?

And another question: when I upload a new version of my store.plist file on my server, the app does’nt update by itself. It must be closed first and then relaunch. I assume I have to put a command in the app delegate file? How do I do that?

Thank you very much!


    If the content is made of PDF files, the text will be rendered perfectly in the new iPad too. As far as graphics, this depends on the DPI (resolution) you used to generate the current PDF (no retina). Usually what you set is a DPI resolution (typically 150) which reflects in a well specified page size, expressed in points (this depends on the paper size of the original magazine). Now with the new iPad you should guarantee a page size of 2048×1536 in order to avoid that the images in the page are stretched. This will impact the final size of the PDF, especially if your magazine contains a log of graphics. So the answer is: first check the graphics content of your PDF. Then it may happen that it is better to distributed two files, one for retina and one for non-retina. What you have to do is to change the URL-generation code that, based on the device scale, will point to the PDF for retina or non-retina. In my opinion the best way to understand this is to load two versions of your magazine on a new iPad and check the final effect. If retina version is much better than non-retina, then the two PDFs are suggested.

    As far as the other question, you should move the “plist loading code” in the “applicationDidBecomeActive:” which is called each time the app enters in the active state (foreground). In this case the store info will be updated each time the user taps the app icon.


Hi, Thank you for this awesome tutorial. I’m trying to present the shelfviewcontroller with in a landscape mode, with 4 items on each row. I did it right by changing the row value from i/3 to i/4. But on the row, the 4th one do not respond to human interaction. Am I missing something? Thank you very much!


    Probably you didn’t change properly the size of the view that contains the covers. So you can still see them, because the view doesn’t clip the subview that lay outside its bounds, but they are not considered by the hit test and so they will not respond to the user interaction. The best way to debug it is to apply to the container view an opaque background color (e.g.: red) and you will probably see those covers outside the colored area.


Hi

Thanks a lot for the post !!
How many days do you think it will take for an experienced C# developer who doesnt know anything about IOS to develop a magazine app with newsstand kit?
I have no idea how much should I charge to my client for development and also publishing issues every month ?

Thanks a lot


I want to create iPad Magazine App.
I want to change pdf file to .html file this tutorial .
How to change this!.



I am a new developer and found your example project to be a great learning too for me. I have modified the UI so that the covers are lined in a single role horizontally with a scroll view. The problem I am having is that when I scroll the covers I see another set of the same images underneath them. I can’t figure out where I have gone wrong but on first run they are not there. If I close the app, when it reloads they are there. Any thoughts on why this could be happening? Again, thanks for this tutorial!!


Ah thats awesome, thats the way i ended up doing it, after a moment on realization. One last thing, how do i get the view to scroll so when there more then 9 or in my case 6 issues ( i customized the layout a lot) it’ll scroll down?


    Basically you will add the cover views inside a UIScrollView container but following the same exact logic as in the app. Clearly the UIScrollView size will have the same size of the view controller view, so when you add a lot of covers they will be placed in coordinates beyond the screen. At the end of the process you will set the scroll view contentSize to the highest Y coordinate and then the scroll view will scroll enough to fit all covers.
    E.g.: let’s say you place all covers in rows which have a pitch of 300, then the first row base will be placed on Y= 350, the second on Y=650, the 3rd on Y=950, the 4th on Y=1250. But 1250 is beyond the screen height of 1024, but if you set the scroll view content size height to 1250 (or slightly more) you will be able to scroll it and see the last row of covers.


Excellent tutorial especially the planning phase. Looking forward for more tutorials of same quality. Thank you


nice guide, Carlo Vigiani how would i get the magazine so the newest one was always the top left one?


    You must sort it by date. Or, better, the server will send them to you in the right order. It is better to leave the server do the sorting job, as the publisher can decide to give more relevance to a magazine instead of another and in such case you don’t need to update the app code again.


Hi,

How can I edit the design in the app?


I tried using this method, after inheriting fastpdfkit as a framework:
-(void)readIssue:(Issue *)issue {
urlOfReadingIssue=[[issue contentURL] URLByAppendingPathComponent:@”magazine.pdf”];
MFDocumentManager *preview = [[MFDocumentManager alloc]initWithFileUrl:urlOfReadingIssue];
/** Instancing the readerViewController */
ReaderViewController *pdfViewController = [[ReaderViewController alloc]initWithDocumentManager:preview];
/** Present the pdf on screen in a modal view */
[self presentModalViewController:pdfViewController animated:YES];

I have no issues in XCode, It shows “build succeeded”, but I just have a black screen on the simulator and in XCode, “attaching file to”. How is it possible? I’m kind of nowhere :s


    Typically when you have this kind of issue just remove the app from the device, close Xcode and restart. It’s like the debugger entered in an unstable state. Of course it’s not related to your code!


Thank you for this awesome tutorial! It was really helpfull! I was wondering, if you want to implement another PDF reader such as fastpdfkit, you have to modify the shelfviewcontroller after -(void)readIssue:(Issue *)issue {

I’m kind of beginner and I can’t managed it to work. Does someone have an idea on how to do it? Thank you very much


    Yes, essentially you must introduce in the “readIssue:” method whatever is required by your external PDF reader. Normally a PDF reader requires at least the path of the pdf file, and this is what I’m doing in my example with the QuickLook framework. E.g. if you use FastPdfKit you must create a MFDocumentManager instance with the pdf path of the document (which is retrievable from the Issue instance), then you will need to create and push in the navigation controller the MFDocumentViewController object that will take care of the PDF reading.
    Consider that in all cases a good PDF reader to be plugged-in in any project needs to be provided as a stand-alone view controller that you can push on top of your window hierarchy. So the approach explained in my tutorial is quite general and works with FastPdfKit for example.


Also how can we make our app available in
Settings – Store – Automatic Downloads category??


    You should register your app for the notification type UIRemoteNotificationTypeNewsstandContentAvailability. At this point the user will be required (at first app run) to allow for automatic download, and based on the answer this settings will be enabled/disabled. The user can clearly change it manually later from the Settings app.


Why the download pauses when the app is suspended??

I think it is suppose to download the content in background..is it so??


    This is in fact a known issue. The download is managed by the internal NK queue and the app has no control of it. I noticed that in some cases the download is suspended, in other cases it continues. There is no special reason for this, probably it’s a bug that will be fixed in later iOS versions. You can open a radar.


thank you for this great tutorial! why did you use the Quick Look Framework? is there any way to make show the issues in a an webview?

thanks in advance for your help


    I just need a quick pdf viewer, both QuickLook and UIWebView do this. Clearly in a real magazine you must develop your own pdf reader or buy an existing component from a 3rd party.


same as Andrew Krowczyk
i put all of my expectatives of digital publishing in Baker Framework and now , its necesary newstand and suscription for this projects.

This would help greatly with the project!!


Please consider popping over to the Baker Framework on Github. There is much discussion over adding the newsstand integration and downloads / etc… This would help greatly with the project!!


Awesome post :-)


This is an amazing tutorial series, I will recommend you publish the final source code of each chapter. I will follow these tutorials.


    I forgot to link the github project. I have updated the post with it. The code is just an example and needs to be fixed in some points, watch it in github for the updates!


Great post! Very useful, Cheers


Leave a Reply

Would you like to sign up to the mailing list by our sister site: SwiftMonthly?