
NSUserDefaults repository (that is, they must be permanently stored between launches of this application) and view them on a separate tab Tab Bar Controller . To do this, based on the previous AdaptiveSplitViewController2Swift application, create a new AdaptiveSplitViewController3Swift application and add a Tab Bar Controller on the storyboard, delete the accompanying View Controllers accompanying it, and instead connect our Photographers to it, inserted into the Navigation Controller and another Resents screen fragment intended for viewing the recent reports photos and also inserted in the navigation controller :
ImageViewController are ImageViewController on the screen modally with a title, but without a navigation bar and without additional buttons on it. But the saddest thing is that we cannot move anywhere from this screen:
ImageViewController on the Navigation Controller stack for the Master , since SplitViewController controls the Master via the Tab Bar Controller , which offers a modal Detail view. To fix this situation, we can put ImageViewController ourselves on the Navigation Controller stack for the Master and will do this in the showDetailViewController method of the showDetailViewController delegate for Compact-width mode.ImageViewController , put it on the Navigation Controller stack for the Master and show it on the screen:
true means that the SplitViewController should not control the Detail display, we will show it ourselves. Now the image of the photo for Compact-width devices will be shown correctly: with the return button and slide as in the Navigation Controller , and not appear modally with the inability to leave it:
ImageViewController to the Navigation Controller stack for the Master , we can get our ImageViewController in the Master when switching to landscape mode, which, of course, is unacceptable, since the ImageViewController should appear only in the Detail view :
ImageViewController from the Navigation Controller stack for Master :
imageURL knowledge of the newly cleaned ImageViewController , we can set up the corresponding line in the list of photos:


ResentsTVC
ResentsTVC class inherits from the FlickrPhotosTVC class and its only functional feature is the reading of a list of photos from NSUserDefaults :
NSUserDefaults organized using the special class ResentsDefault and the var resentsPhotos property of var resentsPhotos :
String and values ​​of type String . Moreover, {get} this property reads data from NSUserDefaults , and {set} NSUserDefaults it to NSUserDefaults . Note that NSUserDefaults is essentially a very small database for permanently storing a Property List of data between the runs of your application. Our internal data structure for storing information about photos received from the Flickr.com server, we chose the [Photo] array, where Photo is a struct and the struct is neither NSDates , nor NSStrings , nor NSArrays , or NSDictionarys . We will not be able to use [Photo] for storage in NSUserDefaults , as this is not the Property List .[[String : String]] dictionaries for storing data on Flickr photos in NSUserDefaults , which is a Property List data, but of course I will need Photo conversion to [[String : String]] and back:
ResentsDefault class, serving interaction with NSUserDefaults , has two properties as a public API :var addedPhoto = Photo? - the photo we want to add to NSUserDefaults ,var resentsPhotos: [[String : String]] - an array of dictionaries with information about photos stored in NSUserDefaults :
NSUserDefaults repository begins with the fact that we add addedPhoto to an existing repository and this is done with one line of code and the addPhoto helper function, which has photo at the entrance and an array of photos resentsPhotos photos stored in NSUserDefaults :addPhoto (photo, inDefaultsPhotos: resentsPhotos)resentsPhotos as an input parameter of an auxiliary function, {get} triggered for this calculated property and the data is read from the NSUserDefaults repository to resentsPhotos . Then we add a new photo photo to the very beginning of the resentsPhotos array as the most “recent”:
resentsPhotos :resentsPhotos = addPhoto (photo, inDefaultsPhotos: resentsPhotos){set} works for this computed property and the updated array is written to the NSUserDefaults repository.NSUserDefaults mechanism NSUserDefaults designed to save a very small amount of data, so we will limit ourselves to the number of photos specified by the ResentPhotoAmount constant, which in our particular case is equal to 20.NSUserDefaults repository. If the user chooses a photo, then we should put the information about it in NSUserDefaults , and this is best done in the prepareForSegue method of the prepareForSegue class, but we will leave this class more general (we may need it for other purposes). Therefore, we will place the new functionality related to the recording of photo information in NSUserDefaults in the new class PhotosSavedNSUserDefaults , which is a subclass of the FlickrPhotosTVC class:
PhotosSavedNSUserDefaults class as a user for the Flickr Photos screen fragment on the storyboard
ResentsTVC class, which serves “recent” photos and Resents screen snippet. His task is to restore information about “recent” photos from NSUserDefaults and we used a single line of code for this:
JustPostedFlickrPhotosTVC , also inheriting from FlickrPhotosTVC :
.flatMap(Photo.init) construction .flatMap(Photo.init) . In the first case, when recovering from NSUserDefaults , [String : String] NSUserDefaults to the input, and in the second case, when reading data from the Flickr server, [String : AnyObject] . How does the compiler know which Photo initializer to run? After all, two of them?
struct can have several initializers, as long as they differ in input parameters. In our case, there are two:init?(json:[String:AnyObject]) , to initialize the struct Photo from the JSON data from the Flickr server,init(userDefaults:[String:String]) , to initialize the struct Photo from the NSUserDefaults repository.struct Photo initializer is called.separateSecondaryViewControllerFromPrimaryViewController showDetailViewController and showDetailViewController delegate UISplitViewControllerDelegate .UIViewController . It appears on the screen using the so-called Popover Presentation Controller mechanism.
prepareForSegue method.

prepareForSegue method for ImageViewController :
prepareForSegue you can get what is called a UIPopoverPresentationController and configure the Popover presentation. For example, you can say that you do not want the Popover to “pop up” to the left of something, but you want the Popover to always “pop up” to the right of something. You can manage all of this. In addition, in the prepareForSegue method, prepareForSegue can define yourself as a delegate:
UIPopoverPresentationControllerDelegate protocol:
UIPopoverPresentationControllerDelegate delegate UIPopoverPresentationControllerDelegate , which returns .None , that is, a “rejection” of iPhone Popover adaptation:
ImageViewController class should remain independent of the way the image URL of the photo is displayed, and the screen fragment that TextView to display the URL of the photo image should be self-adjusting.URLViewController .URLViewController class is the propertyvar url : NSURL?updateUI() user interface is updated using the updateUI() method. We will conduct the entire Popover setting directly in this class, so the URLViewController class confirms the UIPopoverPresentationControllerDelegate protocol:
awakeFromNib “life cycle” awakeFromNib , which is called before everyone else, we set the presentation style .Popover and assign ourselves to the UIPopoverPresentationControllerDelegate protocol UIPopoverPresentationControllerDelegate .
UIPopoverPresentationControllerDelegate , you can impact how the Popover adapts to the iPhone. Popover on the iPad “pops up” like we used to - in the form of a small window. On iPhone, Popover adapts and turns into a full-screen modal window instead of a small window. It doesn't “pop up” like something small on the iPhone. Why? Because the iPhone screen is much smaller, and if the “pop-up” thing is really big, then there may not be a way to make it fit the screen size. But if you present it modally on the whole screen, then it will exactly fit the screen size. iOS automatically makes this adaptation for you, just as Split View Controller and Navigation Controller automatically adapt. But by using the UIPopoverPresentationControllerDelegate delegate, you can impact this adaptation, and that is what we will do..FullScreen returns), but we can say that we want to use UIModalPresentationStyle.None , which means there is no automatic adaptation. That is, the presentation on the iPhone will be exactly the same as on the iPad. For a little popover, this makes a lot of sense. We can “turn off” the behavior of “adaptation” by implementing the delegate method UIPopoverPresentationControllerDelegate , in which we return UIModalPresentationStyle.None :
UIViewController :var preferredContentSize: CGSize


passthroughViews . The whole navigation bar is part of passthroughViews , and the really bad thing is that if I click on another photo in the list, the image of the photo is updated, but the Popover from the URL is not. Still on the screen will be the URL of the old photo. This is really very bad.image , I will dismiss any Popover that I have.

adaptivePresentationStyleForPresentationController method.UIPopoverPresentationControllerDelegate delegate, in which we return the value of UIModalPresentationStyle.None :Source: https://habr.com/ru/post/278781/
All Articles