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 storyboardResentsTVC
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