second tutorial
https://www.youtube.com/watch?v=Fk4ier9Ip94
Core Data is poweful framework on iOS SDK that allows programmer to store and manage the data in Object Oriented way.
In this I’ll explain core data stack :
Core Data stack composed of following layers.
1. Managed Object Model
2. Manged Object Context
3. Data Model
4. Persistant Store Coordinator
5. Persistant Object Store
Managed Object Model : It’s collection of entity descrition, think about it as database schema and It represent our data model. NSManagedObjectModel class is use to implement it. (data model들의 구조들을 기술한다)
Managed Object Context : It keep track of all things we are doing with managed objects, it’s a like a virtual board.
Managed Object : Represent the entity we want to store in core data. In swift NSManagedObject instances are use to represent our data.(하나의 entity를 기술한다.)
Persistant Store : The object that represent actual db on disk. It is responsible to persist the data on disk. (data를 보관하는 하나의 store )
Persistant Store Coordinator : It’s the object that coordinate reading and writing of infofrom and to persistant store. It act as bridge between Managed object context and persistant store. (하나의 application에서도 여러개의 persistant store가 사용될수 있는데 이를 관리해주는 중간역할을 한다)
Core Data with Swift 4 for Beginners – XCBlog – Medium
original source : https://medium.com/xcblog/core-data-with-swift-4-for-beginners-1fc067cca707
Core Data is one of the most popular frameworks provided by Apple for iOS and macOS apps. Core data is used to manage the model layer object in our application. You can treat Core Data as a framework to save, track, modify and filter the data within iOS apps, however, Core Data is not a Database. Core Data is using SQLite as it’s persistent store but the framework itself is not the database. Core Data does much more than databases like managing the object graphs, tracking the changes in the data and many more things. In this short post, we will see how to save and retrieve data using Core Data frameworks.
In order to demonstrate basics of the Core Data, let’s create single view iOS app with Core Data module selected.
Now that, we have created a demo project with Core Data support. There are two notable changes in this Xcode template we can easily observe which are
The Core Data Stack code inside the AppDelegate.swift has clear documentation in form of comments but in short, it set up the persistentContainer(data를 보관하는 방법, 장소 데이터베이스가 될수도 있다. sqlite가 될수도 있다.) and save the data if there are any changes. As AppDelegate is the first file that executes as soon as app launched, we can save and fetch the context the from the Core Data Stack(프로그램이 시작되면 제일 먼저 수행되는 것이 appdelegate화일이므로 이곳에서 콘테이너를 설정한다).
The new fileCoreDataDemo.xcdatamodeld acts as the model layer for the data that we want to save. We can easily ad the entity, attributes and relationships from the UI as like any other relational database.
Now that, let’s say we want to store the username, password and age attributes for the User entity. Select the CoreDataDemo.xcdatamodeld file and click on “Add Entity” (+) button and name the entity as Users. From the add username, password and age as String type attributes. The end result will look like this
Now that, we have modelled our data in the Users entity. It’s time to add some records and save it into the CoreData
The process of adding the records to Core Data has following tasks
Let’s do everything inside theViewController.swift and viewDidLoad() method. As we know that container is set up in the AppDelegates so we need to refer that container.
let appDelegate = UIApplication.shared.delegate as! AppDelegate
We need to create a context from this container.
let context = appDelegate.persistentContainer.viewContext
Now let’s create an entity and new user records.
let entity = NSEntityDescription.entity(forEntityName: "Users", in: context)
let newUser = NSManagedObject(entity: entity!, insertInto: context)
At last, we need to add some data to our newly created record for each keys using
newUser.setValue("Shashikant", forKey: "username")
newUser.setValue("1234", forKey: "password")
newUser.setValue("1", forKey: "age")
Now we have set all the values. The next step is to save them inside the Core Data
The methods for saving the context already exist in the AppDelegate but we can explicitly add this code to save the context in the Database. Note that, we have to wrap this with do try and catch block.
do {
try context.save()
} catch {
print("Failed saving")
}
At this stage, whenever we run our app the new entries will be added to the Core Data records.
The process of fetching the saved data from is very easy as well. It has the following task
We can fetch the data from our Users entity using following code.
let request = NSFetchRequest<NSFetchRequestResult>(entityName: "Users")
//request.predicate = NSPredicate(format: "age = %@", "12")
request.returnsObjectsAsFaults = false
do {
let result = try context.fetch(request)
for data in result as! [NSManagedObject] {
print(data.value(forKey: "username") as! String)
}
} catch {
print("Failed")
}
This will print the value of username from the Core Data. That’s it! Now that, you have successfully saved and fetched data from Core Data.
Well, this isn’t enough to save and retrieve data, there are many complex things we can do with core data like modify, delete, tracking data changes, adding Predicates and complex relationships od databases. As you use more Core Data things get more complex.
The source code for this demo app is on Github as CoreDataDemo repository. You can clone the repo and play with Core Data.
$ git clone git@github.com:Shashikant86/CoreDataDemo.git
$ cd CoreDataDemo
$ open CoreDataDemo.xcodeproj/
Have Fun with Core Data!
Note: This article was originally published on personal blog a.k.a XCBlog here. Checkout my XCBlog site for more interesting things about iOS DevOps, Continuous Integration/Delivery here
original source : https://thatthinginswift.com/guard-statement-swift/
Guard Statements
guard
and defer
joined us in Swift 2.0 to little fanfare. Both use cases were somewhat obvious initially and plenty of articles were written about how to use these features. guard
in particular seemed to solve a few sticky problems that Swift programmers got into frequently but a more in-depth exploration of real world usage of these concepts was lacking. We’ll cover guard
today and possibly defer
in the future.
Guard combines two powerful concepts that we’re already used to in Swift: optional unwrapping and where clauses. The former allows us to avoid the pyramid of doom or its alternative, the very long if let
statement. The latter attaches simple but powerful expressions with the where
clause so we can further vet the results we’re validating.
When to use
guard
If you’ve got a view controller with a few UITextField
elements or some other type of user input, you’ll immediately notice that you must unwrap the textField.text
optional to get to the text inside (if any!). isEmpty
won’t do you any good here, without any input the text field will simply return nil.
So you have a few of these which you unwrap and eventually pass to a function that posts them to a server endpoint. We don’t want the server code to have to deal with nil
values or mistakenly send invalid values to the server so we’ll unwrap those input values with guard first.
func submit() { guard let name = nameField.text else { show("No name to submit") return } guard let address = addressField.text else { show("No address to submit") return } guard let phone = phoneField.text else { show("No phone to submit") return } sendToServer(name, address: address, phone: phone) } func sendToServer(name: String, address: String, phone: String) { ... }
You’ll notice that our server communication function takes non-optional String
values as parameters, hence the guard unwrapping beforehand. The unwrapping is a little unintuitive because we’re used to unwrapping with if let
which unwraps values for use inside a block. Here the guard statement has an associated block but it’s actually an else
block – i.e. the thing you do if the unwrapping fails – the values are unwrapped straight into the same context as the statement itself.
// separation of concerns
Without
guard
Without using guard
, we’d end up with a big pile of code that resembles a pyramid of doom. This doesn’t scale well for adding new fields to our form or make for very readable code. Indentation can be difficult to follow, particularly with so many else
statements at each fork.
func nonguardSubmit() { if let name = nameField.text { if let address = addressField.text { if let phone = phoneField.text { sendToServer(name, address: address, phone: phone) } else { show("no phone to submit") } } else { show("no address to submit") } } else { show("no name to submit") } }
Yes, we could even combine all these if let
statements into a single statement separated with commas but we would loose the ability to figure out which statement failed and present a message to the user.
If you start seeing this kind of code appear in one of your view controllers, it’s time to start thinking about how to do the same thing with guard
.
Validation and testing with
guard
One argument against using guard is that it encourages large and less testable functions by combining tests for multiple values all in the same place. If used naïvely this could be true but with the proper use, guard
allows us to smartly separate concerns, letting the view controller deal with managing the view elements while the validation for these elements can sit in a fully tested validation class or extension.
Let’s take a look at this naïvely constructed guard
statement with validation:
guard let name = nameField.text where name.characters.count > 3 && name.characters.count <= 16, let range = name.rangeOfCharacterFromSet(NSCharacterSet.whitespaceAndNewlineCharacterSet()) where range.startIndex == range.endIndex else { show("name failed validation") return } submit(name)
You can probably tell we’re stuffing too much functionality into a single line here. Not only do we check for existence of the name field, we also check that the name is between 3 and 16 characters in length and that it contains no newlines or whitespaces. This is busy enough to be nearly unreadable, and it’s unlikely to be tested because we can’t validate the name field without interacting with the UI and submitting the name to the server.
Realistically, this view controller could be handling 5 inputs and each should be checked for validity before it’s submitted. Each one could look just like this, leading to a truly massive view controller.
Here’s a better example of real world guard
usage.
func tappedSubmitButton() { guard let name = nameField.text where isValid(name) else { show("name failed validation") return } submit(name) } func isValid(name: String) -> Bool { // check the name is between 4 and 16 characters if !(4...16 ~= name.characters.count) { return false } // check that name doesn't contain whitespace or newline characters let range = name.rangeOfCharacterFromSet(.whitespaceAndNewlineCharacterSet()) if let range = range where range.startIndex != range.endIndex { return false } return true }
You’ll notice a few differences in the updated version. First, our name validation function is separated into a testable validation function (located either in your view controller or in a different, fully tested class depending on your preferences). isValid
has clearly marked steps for validating a name: a length check and a character check.
Instead of cramming all that validation into the where clause, we simply call the isValid
function from the where clause, failing the guard
statement if the text is nil or fails validation.
Testing is great but the best part of this implementation is the clarity of code. tappedSubmitButton
has a very small responsibility, much of which is unlikely to fail. View controllers are difficult to test on iOS using standard MVC organization (which, despite many new players, is still the clearest organizational pattern) so minimizing their responsibility or likelihood of failure is an important part of architecting your iOS app.
guard
has clear use cases but can be tempting to use as part of a massive view controller. Separating your guard
validation functions allows you to maintain more complex view controllers without loosing clarity or readability.
참고사항 )
multiple condition guard
https://stackoverflow.com/questions/39198626/multiple-conditions-in-guard-statement-swift
guard case
https://www.quora.com/Can-you-combine-a-guard-and-a-switch-statement-in-Swift
It’s not quite clear what you mean. You can certainly have guards inside the cases of a switch statement, or have a switch statement within the else block of a guard. If you mean that you want to combine the simple layout of a guardstatement with the sophisticated pattern match of a switch’s cases, you can also use the guard case statement to do that:
guard case .scalarValue(let scalar) = utf8Decoder.decode(&byteIterator) else {
throw MyError.noUnicodeScalar
}
myString.unicodeScalars.append(scalar)
The if, for, and while statements also support pattern matches like these.
UICollectionView Tutorial: Getting Started
Note: This tutorial has been updated for Swift 3, iOS 10, and Xcode 8.
The iOS Photos app has a stylish way of displaying photos via a multitude of layouts. You can view your photos in a nice grid view:
Or you can view your albums as stacks:
You can even transition between the two layouts with a cool pinch gesture. “Wow, I want that in my app!”, you may think.
UICollectionView
makes adding your own custom layouts and layout transitions (like those in the Photos app) simple to build.
You’re by no means limited to stacks and grids, because collection views are extremely customizable. You can use them to make circle layouts, cover-flow style layouts, Pulse news style layouts – almost anything you can dream up!
The good news is, if you’re familiar with UITableView
, you’ll have no problem picking up collection views – using them is very similar to the table view data source and delegate pattern.
In this tutorial, you’ll get hands-on experience with UICollectionView
by creating your own grid-based photo browsing app. By the time you are done with this tutorial, you will know the basics of using collection views and will be ready to start using this amazing technology in your apps!
Let’s go right to an example of the finished project. UICollectionView
contains several key components, as you can see below:
Take a look at these components one-by-one:
UICollectionView
– the main view in which the content is displayed, similar to a UITableView
. Like a table view, a collection view is a UIScrollView
subclass.UICollectionViewCell
– similar to a UITableViewCell
in a table view. These cells make up the content of the view and are added as subviews to the collection view. Cells can be created programmatically or inside Interface Builder.Supplementary Views
– if you have extra information you need to display that shouldn’t be in the cells but still somewhere within the collection view, you should use supplementary views. These are commonly used for headers or footers.Note: Collection views can also have Decoration Views – if you want to add some extra views to enhance the appearance of the collection view (but don’t really contain useful data), you should use decoration views. Background images or other visual embellishments are good examples of decoration views. You won’t be using decoration views in this tutorial as it requires you to write a custom layout class.
In addition to the above visual components, a collection view has a layout object which is responsible for the size, position and several other attributes of the content. Layout objects are subclasses of UICollectionViewLayout
. Layouts can be swapped out during runtime and the collection view can even automatically animate switching from one layout to another!
You can subclass UICollectionViewLayout
to create your own custom layouts, but Apple has graciously provided developers with a basic “flow-based” layout called UICollectionViewFlowLayout
. It lays elements out one after another based on their size, quite like a grid view. You can use this layout class out of the box, or subclass it to get some interesting behavior and visual effects.
You will learn more about these elements in-depth throughout this tutorial and the next. But for now, it’s time for you to get your hands into the mix with a project!
In the rest of this tutorial, you are going to create a cool photo browsing app called FlickrSearch. It will allow you to search for a term on the popular photo sharing site Flickr, and it will download and display any matching photos in a grid view, as you saw in the screenshot earlier.
Ready to get started? Fire up Xcode and go to FileNewProject… and select the iOSApplicationSingle View Application template.
This template will provide you with a simple UIViewController and storyboard to start out with, and nothing more. It’s a good “almost from scratch” point to start from.
Click Next to fill out the information about the application. Set the Product Name to FlickrSearch, the device type to iPad and the language to Swift. Click Next to select the project location, and then click Create.
The view controller subclass and storyboard that come with the single view application template aren’t any use to you – you’re going to use a UICollectionViewController
, which, like a UITableViewController
, is a specialized view controller subclass designed to host a collection view. Delete ViewController.swiftand remove the empty view controller from Main.storyboard. Now you’ve got a really blank slate :].
Open AppDelegate.swift and add a constant to hold a delightful shade I call Wenderlich Green. Add the following underneath the import UIKit
line:
let themeColor = UIColor(red: 0.01, green: 0.41, blue: 0.22, alpha: 1.0)
Use Wenderlich Green as a theme color for the whole app. Update application(_:didFinishLaunchingWithOptions:)
to the following:
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool { window?.tintColor = themeColor return true }
Open Main.storyboard and drag in a Collection View Controller. Go to EditorEmbed inNavigation Controller to create a navigation controller and automatically set the collection view controller as the root.
You should now have a layout like this in the storyboard:
Next, select the Navigation Controller you installed and make it the initial view controller in the Attributes Inspector:
Next, focusing on the collection view controller, select the UICollectionView
inside and change the background color to White Color:
Note: Wondering what the Scroll Direction property does? This property is specific to UICollectionViewFlowLayout
, and defaults to Vertical. A vertical flow layout means the layout class will place items from left to right across the top of the view until it reaches the view’s right edge, at which point it moves down to the next line. If there are too many elements to fit in the view at once, the user will be able to scroll vertically to see more.
Conversely, a horizontal flow layout places items from top to bottom across the left edge of the view until it reaches the bottom edge. Users would scroll horizontally to see items that don’t fit on the screen. In this tutorial, you’ll stick with the more common Vertical collection view.
Select the single cell in the collection view and set the Reuse Identifier to FlickrCell using the attributes inspector. This should also be familar from table views – the data source will use this identifier to dequeue or create new cells.
Drag in a text field to the center of the navigation bar above the collection view. This will be where the user enters their search text. Set the Placeholder Text of the search field to Search and the Return Keyto Search in the attributes inspector:
Next, control-drag from the text field to the collection view controller and choose the delegate outlet:
UICollectionViewController
does a lot, but you generally need to make a subclass. Do this now. Go to FileNewFile…, choose iOSSourceCocoa Touch Class template and click Next. Name the new class FlickrPhotosViewController, making it a subclass of UICollectionViewController
. There’s a lot of code added by the template, but the best way to understand what this class does is to start from scratch. Open FlickrPhotosViewController.swift replace the contents of the file with the below code:
import UIKit final class FlickrPhotosViewController: UICollectionViewController { // MARK: - Properties fileprivate let reuseIdentifier = "FlickrCell" }
Next, add a constant for section insets (which you’ll use later) right below the reuseIdentifier constant:
fileprivate let sectionInsets = UIEdgeInsets(top: 50.0, left: 20.0, bottom: 50.0, right: 20.0)
You’ll be filling in the rest of the gaps as you progress through the tutorial.
Go back to Main.storyboard, select the collection view controller and in the identity inspector, set the Class to FlickrPhotosViewController to match your new class:
You first task for this section is to say the section title ten times fast. OK, just kidding.
Flickr is a wonderful image sharing service that has a publicly accessible and dead- simple API for developers to use. With the API you can search for photos, add photos, comment on photos, and much more.
To use the Flickr API, you need an API key. If you are doing a real project, I recommend you sign up for one here: http://www.flickr.com/services/api/keys/apply/.
However, for test projects like this, Flickr has a sample key they rotate out every so often that you can use without having to sign up. Simply perform any search at: http://www.flickr.com/services/api/explore/?method=flickr.photos.search and copy the API key out of the URL at the bottom – it follows the “&api_key=” all the way to the next “&”. Paste it somewhere in a text editor for later use.
For example, if the URL is:
http://api.flickr.com/services/rest/?method=flickr.photos.search&api_key=6593783 efea8e7f6dfc6b70bc03d2afb&format=rest&api_sig=f24f4e98063a9b8ecc8b522b238 d5e2f
Then the API key is: 6593783efea8e7f6dfc6b70bc03d2afb
Note: If you use the sample API key, note that it is changed nearly every day. So if you’re doing this tutorial over the course of several days, you might find that you have to get a new API key often. For this reason it might be easier to get an API key of your own from Flickr if you think you’re going to spend several days on this project.
Since this tutorial is about UICollectionView
and not the Flickr API, a set of classes has been created for you that abstracts the Flickr search code. You can download them here.
Unzip and drag the files into your project, making sure that the box Copy items into destination group’s folder (if needed) is checked, and click Finish.
The file contains two classes and a struct:
FlickrSearchResults
: A struct which wraps up a search term and the results found for that search.FlickrPhoto
: Data about a photo retrieved from Flickr – its thumbnail, image, and metadata information such as its ID. There are also some methods to build Flickr URLs and some size calculations. FlickrSearchResults
contains an array of these objects.Flickr
: Provides a simple block-based API to perform a search and return a FlickrSearchResult
Feel free to take a look at the code – it’s pretty simple and might inspire you to make use of Flickr in your own projects!
Before you can search Flickr, you need to enter an API key. Open Flickr.swift and replace the value of apiKey
with the API key you obtained earlier. It should look something like this:
let apiKey = "hh7ef5ce0a54b6f5b8fbc36865eb5b32"
When you’re ready to go, move on to the next section – it’s time to do a little prep work before hooking into Flickr.
Preparing Data Structures
You’re going to build this project so that after each time you perform a search, it displays a new sectionin the collection view with the results (rather than simply replacing the previous section). In other words, if you search for “ninjas” and then “pirates”, there will be a section of ninjas and a section of pirates in the collection view. Talk about a recipe for disaster!
To accomplish this, you’re going to need a data structure so you can keep the data for each section separate. An array of FlickrSearchResults
will do the trick nicely.
Open FlickrPhotosViewController.swift and the following properties below the sectionInsets constant:
fileprivate var searches = [FlickrSearchResults]() fileprivate let flickr = Flickr()
searches
is an array that will keep track of all the searches made in the app, and flickr
is a reference to the object that will do the searching for you. Next, add the following private extension to the bottom of the file:
// MARK: - Private private extension FlickrPhotosViewController { func photoForIndexPath(indexPath: IndexPath) -> FlickrPhoto { return searches[(indexPath as NSIndexPath).section].searchResults[(indexPath as IndexPath).row] } }
photoForIndexPath
is a convenience method that will get a specific photo related to an index path in your collection view. You’re going to access a photo for a specific index path a lot, and you don’t want to repeat code.
Getting Good Results
You are now ready to get your Flickr search on! You want to trigger a search when the user hits Searchafter typing in a query. You already connected the text field’s delegate outlet to your collection view controller, now you can do something about it.
Open FlickrPhotosViewController.swift and add an extension to hold the text field delegate methods:
extension FlickrPhotosViewController : UITextFieldDelegate { func textFieldShouldReturn(_ textField: UITextField) -> Bool { // 1 let activityIndicator = UIActivityIndicatorView(activityIndicatorStyle: .gray) textField.addSubview(activityIndicator) activityIndicator.frame = textField.bounds activityIndicator.startAnimating() flickr.searchFlickrForTerm(textField.text!) { results, error in activityIndicator.removeFromSuperview() if let error = error { // 2 print("Error searching : (error)") return } if let results = results { // 3 print("Found (results.searchResults.count) matching (results.searchTerm)") self.searches.insert(results, at: 0) // 4 self.collectionView?.reloadData() } } textField.text = nil textField.resignFirstResponder() return true } }
textFieldShouldReturn 사용자가 return 버튼을 누를 경우 호출된다.
resignFirstResponder 이함수를 포함하고 호출한 view를 window로부터 first responder가 아닌것으로 만든다.
https://developer.apple.com/documentation/uikit/uiresponder/1621097-resignfirstresponder
Here is an explanation of the code:
reloadData()
method, which works just like it does in a table view.Go ahead and run your app. Perform a search in the text box, and you should see a log message in the console indicating the number of search results, similar to this:
Found 20 matching bananas
Note that the results are limited to 20 by the Flickr class to keep load times down.
Unfortunately, you don’t see any photos in your collection view! Just like a table view, a collection view doesn’t do much unless you implement the relevant data source and delegate methods.
Feeding the UICollectionView
As you probably already know, when you use a table view you have to set a data source and a delegate in order to provide the data to display and handle events (like row selection).
Similarly, when you use a collection view you have to set a data source and a delegate as well. Their roles are the following:
UICollectionViewDataSource
) returns information about the number of items in the collection view and their views.UICollectionViewDelegate
) is notified when events happen such as cells being selected, highlighted, or removed.UICollectionViewFlowLayout
also has a delegate protocol – UICollectionViewDelegateFlowLayout
. It allows you to tweak the behaviour of the layout, configuring things like the cell spacing, scroll direction, and more.
In this section, you’re going to implement the required UICollectionViewDataSource
and UICollectionViewDelegateFlowLayout
methods on your view controller, so you are all set up to work with your collection view. The UICollectionViewDelegate
methods aren’t needed for this part, but you’ll be using them in part 2.
UICollectionViewDataSource
Open FlickrPhotosViewController.swift, add the following extension to the file for the UICollectionViewDataSource
protocol:
// MARK: - UICollectionViewDataSource extension FlickrPhotosViewController { //1 override func numberOfSections(in collectionView: UICollectionView) -> Int { return searches.count } //2 override func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int { return searches[section].searchResults.count } //3 override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { let cell = collectionView.dequeueReusableCell(withReuseIdentifier: reuseIdentifier, for: indexPath) cell.backgroundColor = UIColor.black // Configure the cell return cell } }
These methods are pretty straightforward:
searches
array.searchResults
array from the relevant FlickrSearch
object.Build and run again, and perform a search. You should see 20 new cells, albeit looking a little dull at the moment:
UICollectionViewFlowLayoutDelegate
As I mentioned early in the section, every collection view has an associated layout. You’re using the pre-made flow layout for this project, since it’s nice and easy to use and gives you the grid-view style you’re looking for.
Still in FlickrPhotosViewController.swift, add the following constant below your flickr
constant:
fileprivate let itemsPerRow: CGFloat = 3
Next, add the UICollectionViewDelegateFlowLayout
extension to allow the view controller to conform to the flow layout delegate protocol:
extension FlickrPhotosViewController : UICollectionViewDelegateFlowLayout { //1 func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize { //2 let paddingSpace = sectionInsets.left * (itemsPerRow + 1) let availableWidth = view.frame.width - paddingSpace let widthPerItem = availableWidth / itemsPerRow return CGSize(width: widthPerItem, height: widthPerItem) } //3 func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAt section: Int) -> UIEdgeInsets { return sectionInsets } // 4 func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumLineSpacingForSectionAt section: Int) -> CGFloat { return sectionInsets.left } }
collectionView(_:layout:sizeForItemAt:)
is responsible for telling the layout the size of a given cellcollectionView(_:layout:insetForSectionAt:)
returns the spacing between the cells, headers, and footers. A constant is used to store the value.Build and run again, and perform a search. Behold! Black squares that are bigger than before!
With this infrastructure in place, you are now ready to actually display some photos on screen!
One of the great things about UICollectionView
is that, like table views, it is easy to set up collection views visually in the Storyboard editor. You can drag and drop collection views into your view controller, and design the layout for your cells right from within the Storyboard editor! Let’s see how it works.
Open Main.storyboard and select the collection view. Give yourself a bit of room to work by setting the cell size to 200×200 in the size inspector:
Note: Setting this size doesn’t affect the cells in your app, because you’ve implemented the delegate method to give a size for each cell, which overwrites anything set in the storyboard.
Drag an image view onto the cell and stretch it so it perfectly takes up the entire cell. With the image view still selected, open the pin menu, uncheck Constrain to margins and add constraints of 0 points all the way round:
With the image view still selected, change its Mode to Aspect Fit, so the images are not cropped or stretched in any way:
UICollectionViewCell
doesn’t allow for much customization beyond changing the background color. You will almost always want to create your own subclass, to allow you to easily access any content subviews you have added.
Choose FileNewFile… and choose iOSSourceCocoa Touch Class template and click Next. Name the new class FlickrPhotoCell, making it a subclass of UICollectionViewCell
.
Open Main.storyboard and select the cell. In the identity inspector, set the cell’s class to FlickrPhotoCell:
Open the Assistant editor, making sure it is displaying FlickrPhotoCell.swift and control-drag from the image view to the class to add a new outlet, naming it imageView:
Now you have a custom cell class with an image view. It’s time to put a photo on it! Open FlickrPhotosViewController.swift and replace collectionView(_:cellForItemAtIndexPath:)
with the following:
override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { //1 let cell = collectionView.dequeueReusableCell(withReuseIdentifier: reuseIdentifier, for: indexPath) as! FlickrPhotoCell //2 let flickrPhoto = photoForIndexPath(indexPath: indexPath) cell.backgroundColor = UIColor.white //3 cell.imageView.image = flickrPhoto.thumbnail return cell }
This is a little different from the placeholder method you defined earlier.
FlickrPhotoCell
FlickrPhoto
representing the photo to display, using the convenience method from earlierBuild and run, perform a search and you’ll finally see the pictures you’ve been searching for!
Yes! Success!
Note: If your view doesn’t look like this or the photos are acting weird, it likely means your Auto Layout settings aren’t correct. If you get stuck, try comparing your settings to the solution for this project.
At this point, you’ve now got a complete working (and quite cool) example of UICollectionView
– give yourself a pat on the back! Here’s a link to the finished project: FlickrSearch
But there’s more! Checkout part 2 of this tutorial, where you will learn:
In the meantime, if you have any questions or comments on what you’ve learned so far, please join the forum discussion below!
What is an IndexPath? – free Swift 4 example code
original source : https://www.hackingwithswift.com/example-code/uikit/what-is-an-indexpath
Index paths describe an item’s position inside a table view or collection view, storing both its section and its position inside that section. For example, the first row in a table would have section 0, row 0, whereas the eighth row in the fourth section would have section 3, row 7.
You’ll be given index paths fairly frequently by iOS, for example when the user tapped on a row, or when UIKit needs to know whether a certain item can be edited.
When working with collection views, you should use the item number of an index path rather than its row number, because row numbers mean different things when multiple items can share the same row.
Available from iOS 6.0