I am using the https://www.raywenderlich.com/122148/firebase-tutorial-real-time-chat and I have reached "Creating Messages" portion and my collection view seems to never have been called. I had to take out all the override statement before the collection view functions because I was getting errors with them. I have tried reloading the collection view with
self.collectionView!.reload()
Any ideas?
Here is my code:
Created by Ari on 7/19/16.
// Copyright © 2016 Logical Nonsense LLC. All rights reserved.
//
import UIKit
import JSQMessagesViewController
class ChatViewController: JSQMessagesViewController {
var messages = [JSQMessage]()
var outgoingBubbleImageView: JSQMessagesBubbleImage!
var incomingBubbleImageView: JSQMessagesBubbleImage!
override func viewDidLoad() {
super.viewDidLoad()
self.collectionView!.reloadData()
print("hi")
title = "ChatChat"
setupBubbles()
// Do any additional setup after loading the view.
collectionView!.collectionViewLayout.incomingAvatarViewSize = CGSize(width: 0, height: 0)
collectionView!.collectionViewLayout.outgoingAvatarViewSize = CGSize(width: 0, height: 0)
addMessage(id: "foo", text: "Hey person!")
// messages sent from local sender
addMessage(id: senderId, text: "Yo!")
addMessage(id: senderId, text: "I like turtles!")
print("hi")
// animates the receiving of a new message on the view
finishReceivingMessage()
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
self.collectionView!.reloadData()
// messages from someone else
addMessage(id: "foo", text: "Hey person!")
// messages sent from local sender
addMessage(id: senderId, text: "Yo!")
addMessage(id: senderId, text: "I like turtles!")
print("hi")
// animates the receiving of a new message on the view
finishReceivingMessage()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func collectionView(collectionView: JSQMessagesCollectionView!,
messageDataForItemAtIndexPath indexPath: NSIndexPath!) -> JSQMessageData! {
return messages[indexPath.item]
}
func collectionView(collectionView: UICollectionView,
numberOfItemsInSection section: Int) -> Int {
return messages.count
}
override func viewDidDisappear(_ animated: Bool) {
super.viewDidAppear(true)
}
func collectionView(collectionView: JSQMessagesCollectionView!, messageBubbleImageDataForItemAtIndexPath indexPath: NSIndexPath!) -> JSQMessageBubbleImageDataSource! {
let message = messages[indexPath.item] // 1
if message.senderId == senderId { // 2
return outgoingBubbleImageView
} else { // 3
return incomingBubbleImageView
}
}
func collectionView(collectionView: JSQMessagesCollectionView!,
avatarImageDataForItemAtIndexPath indexPath: NSIndexPath!) -> JSQMessageAvatarImageDataSource! {
return nil
}
func addMessage(id: String, text: String) {
print(text)
let message = JSQMessage(senderId: id, displayName: "", text: text)
messages.append(message!)
self.collectionView!.reloadData()
}
private func setupBubbles() {
let factory = JSQMessagesBubbleImageFactory()
outgoingBubbleImageView = factory?.outgoingMessagesBubbleImage(
with: UIColor.jsq_messageBubbleBlue())
incomingBubbleImageView = factory?.incomingMessagesBubbleImage(
with: UIColor.jsq_messageBubbleLightGray())
}
/*
// MARK: - Navigation
// In a storyboard-based application, you will often want to do a little preparation before navigation
override func prepare(for segue: UIStoryboardSegue, sender: AnyObject?) {
// Get the new view controller using segue.destinationViewController.
// Pass the selected object to the new view controller.
}
*/
}
Related
I am working with JSQMessagesViewController and Firebase to implement a chat feature in my app. I had everything working well in my ChatViewController. But now I have moved my ChatViewController into a container view that is within a parent view controller and now the "send" button does not work when the keyboard is expanded.
In other words, in order to send a chat message, I must call view.endEditing(true) on the parent view controller that itself is within a UITabBarController, and then the send button will work. But as long as the keyboard is expanded, the send button doesn't respond. below is my ChatViewController code...
import Foundation
import UIKit
import FirebaseDatabase
import JSQMessagesViewController
final class ChatViewController: JSQMessagesViewController {
var outgoingBubbleImageView: JSQMessagesBubbleImage!
var incomingBubbleImageView: JSQMessagesBubbleImage!
var fireRootRef: FIRDatabaseReference!
var chatMessages = [JSQMessage]()
var messagesRefHandle: UInt!
var chatChannelId: String!
override func viewDidLoad(){
super.viewDidLoad()
self.inputToolbar.contentView.textView.backgroundColor = UIColor.clear
inputToolbar.alpha = 0.7
...
}
override func viewWillAppear(_ animated: Bool){
super.viewWillAppear(animated)
}
override func viewDidAppear(_ animated: Bool){
super.viewDidAppear(animated)
}
func setupView(){
...
}
override func viewWillDisappear(_ animated: Bool) {
super.viewDidDisappear(animated)
removeChatObserver()
}
func removeChatObserver(){
...
}
private func setupMessageBubbles() {
...
}
override func collectionView(_ collectionView: UICollectionView,
numberOfItemsInSection section: Int) -> Int {
return chatMessages.count
}
override func collectionView(_ collectionView: JSQMessagesCollectionView!, messageBubbleImageDataForItemAt indexPath: IndexPath!) -> JSQMessageBubbleImageDataSource! {
let message = chatMessages[indexPath.item]
if message.senderId == senderId {
return outgoingBubbleImageView
} else {
return incomingBubbleImageView
}
}
override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = super.collectionView(collectionView, cellForItemAt: indexPath) as! JSQMessagesCollectionViewCell
let message = chatMessages[indexPath.item]
if message.senderId == senderId {
cell.textView!.textColor = UIColor.white
} else {
cell.textView!.textColor = UIColor.black
}
return cell
}
override func collectionView(_ collectionView: JSQMessagesCollectionView!, layout collectionViewLayout: JSQMessagesCollectionViewFlowLayout!, heightForMessageBubbleTopLabelAt indexPath: IndexPath!) -> CGFloat {
let message = chatMessages[indexPath.item]
if message.senderId == self.senderId {
return 0
}
if indexPath.item > 0 {
let previousMessage = chatMessages[indexPath.item - 1]
if previousMessage.senderId == message.senderId {
return 0
}
}
return kJSQMessagesCollectionViewCellLabelHeightDefault
}
override func collectionView(_ collectionView: JSQMessagesCollectionView!, attributedTextForMessageBubbleTopLabelAt indexPath: IndexPath!) -> NSAttributedString! {
let message = chatMessages[indexPath.item]
switch message.senderId {
case senderId:
return nil
default:
guard let senderDisplayName = message.senderDisplayName else {
assertionFailure()
return nil
}
return NSAttributedString(string: senderDisplayName)
}
}
//no avatar images
override func collectionView(_ collectionView: JSQMessagesCollectionView!, avatarImageDataForItemAt indexPath: IndexPath!) -> JSQMessageAvatarImageDataSource! {
return nil
}
override func didPressSend(_ button: UIButton!, withMessageText text: String!, senderId: String!, senderDisplayName: String!, date: Date!) {
print("DID PRESS SEND")
let fireMessagesRef = fireRootRef.child("messages").child(chatChannelId)
let itemRef = fireMessagesRef.childByAutoId()
let messageItem = [
"text": text,
K.MessageKeys.senderIdKey: senderId,
"displayName": senderDisplayName,
]
itemRef.setValue(messageItem)
JSQSystemSoundPlayer.jsq_playMessageSentSound()
finishSendingMessage()
}
override func didPressAccessoryButton(_ sender: UIButton!) {
//
}
private func observeMessages() {
...
}
func addMessage(id: String, text: String, name: String) {
...
}
}
I would like to fix the send button so the user can tap send when the keyboard is expanded. It is interesting that in order to dismiss the keyboard I have to call view.endEditing(true) on the parent view controller and not on the child view itself. This made me think that I need to configure the button action on the parent view however i haven't had any success. Thanks for your help
What I guess is jsq collection view cover the input view, so you are pressing on collection view, not the send button. Put a breakpoint on - (void)jsq_didReceiveKeyboardWillChangeFrameNotification:(NSNotification *)notification in JSQMessagesViewController, check whether CGRectGetHeight(keyboardEndFrame) and insets.bottom for setting collection view bottom is sufficient space to show the input view in your container. A problem is that the jsq controller use autolayout to adjust subviews, the collection view is align with its topLayoutGuide and bottomLayoutGuide which is the view controller thing, when you put a view controller inside another view controller, that may cause confusion.
Take iPhone 6(s)/7 plus for example, the keyboard height is 271, the inputtoolbar is 44 height in controller, so the total height is 315. Therefore CGRectGetHeight(keyboardEndFrame) + insets.bottom should be 315. Put a breakpoint on that line, check whether the sum is 315, if not, that means something calculated wrong.
Update for solution
If the cause is indeed mentioned above, try this to solve the problem
self.additionalContentInset = UIEdgeInsets(top: 0, left: 0, bottom: 44, right: 0)
This will add a bottom inset to the collection view. Add this after viewDidLoad
I am using realm for my notepad app to store the array noteTitles, which is of a custom class Note. The app works fine, but when it is supposed to save, it doesn't pass through. When I restart the app, the notes are gone. I will give code to all of the files. Also, I want the user to add notes and I need the ObjectForPrimaryKey to update everytime so a new id is created for each note.
Note Class Code:
import Foundation
import RealmSwift
class Note: Object {
dynamic var title = ""
var content = ""
var id = 0
override class func primaryKey() -> String? {
print("id generated")
return "id"
}
}
ViewController(Where I write the notes) Code:
import UIKit
import RealmSwift
var note2 = Note()
var note: Note!
let realm = try! Realm()
class ViewController3: UIViewController, UITextViewDelegate {
var note: Note!
#IBOutlet var noteText: UITextView!
#IBOutlet var noteTitle: UITextField!
override func viewWillAppear(animated: Bool) {
super.viewWillAppear(animated)
noteTitle.text = note.title
noteText.text = note.content
}
override func viewWillDisappear(animated: Bool) {
super.viewWillDisappear(animated)
note.title = noteTitle.text!
note.content = noteText.text
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func textViewDidEndEditing(textView: UITextView) {
func noteEnded(note2: Note) {
note2.title = note.title
note2.content = note.content
note2.id = note.id
do {
try realm.write {
realm.add(noteTitles, update: true)
print("added")
}
} catch {
print("There was a problem")
}
}
print("editing ended")
}
override func viewDidLoad() {
super.viewDidLoad()
print(note2.id)
self.noteText.delegate = self
// Do any additional setup after loading the view.
}
override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
self.view.endEditing(true)
noteTitle.resignFirstResponder()
noteText.resignFirstResponder()
}
}
TableViewController(Note List) Code:
import UIKit
import RealmSwift
var noteTitles:[Note] = []
class TableViewController: UITableViewController {
// MARK: - Table view data source
override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
// #warning Incomplete implementation, return the number of sections
return 1
}
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
// #warning Incomplete implementation, return the number of rows
return noteTitles.count
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("cell", forIndexPath: indexPath) as UITableViewCell
cell.textLabel!.text = noteTitles[indexPath.row].title // error here
// Configure the cell...
return cell
}
override func viewDidAppear(animated: Bool) {
tableView.reloadData()
}
override func viewDidLoad() {
super.viewDidLoad()
sleep(2)
if realm.objectForPrimaryKey(Note.self, key: 0) != nil {
realm.objectForPrimaryKey(Note.self, key: 0)
}
// Uncomment the following line to preserve selection between presentations
// self.clearsSelectionOnViewWillAppear = false
// Uncomment the following line to display an Edit button in the navigation bar for this view controller.
// self.navigationItem.rightBarButtonItem = self.editButtonItem()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
override func tableView(tableView: UITableView, commitEditingStyle editingStyle: UITableViewCellEditingStyle, forRowAtIndexPath indexPath: NSIndexPath) {
if editingStyle == UITableViewCellEditingStyle.Delete {
noteTitles.removeAtIndex(indexPath.row)
tableView.reloadData()
}
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier! == "editNote" {
let noteDetailViewController = segue.destinationViewController as! ViewController3
let selectedIndexPath = tableView.indexPathForSelectedRow
noteDetailViewController.note = noteTitles[selectedIndexPath!.row]
} else if segue.identifier! == "addNote" {
let note = Note()
noteTitles.append(note)
let noteDetailViewController = segue.destinationViewController as! ViewController3
noteDetailViewController.note = note
}
}
}
Thanks in advance!
The function noteEnded should not inside the textViewDidEndEditing and it is not being called.
Try this
func noteEnded(note2: Note) {
do {
try realm.write {
realm.add(note2, update: true)
print("added")
}
} catch {
print("There was a problem")
}
}
func textViewDidEndEditing(textView: UITextView) {
note2.title = note.title
note2.content = note.content
note2.id = note.id
noteEnded(note2)
print("editing ended")
}
It is also better to have "Done" button to save the note. Easy to handle the input and save.
I have a ViewController that shows the user more information, then they click on a button and it sends them to my messageView which is a JSQ ViewController. The JSQViewController uses the collection View classes. When the user navigates back to the more information view and then hits the button to navigate to the message view again, the collection view duplicates my chat bubbles. I think I need to reset something to nil, but I am not sure what to set and where to set it. Here is my code:
import UIKit
import Firebase
import JSQMessagesViewController
// MARK: Properties
var messages = [JSQMessage]()
var outgoingBubbleImageView: JSQMessagesBubbleImage!
var incomingBubbleImageView: JSQMessagesBubbleImage!
let rootReference = FIRDatabase.database().referenceFromURL("myHTTPSLINK")
var messageReference: FIRDatabaseReference!
var dataBaseMessageRef: FIRDatabaseReference!
class ChatViewController: JSQMessagesViewController{
var userContacedID: String = ""
var userToBeChatted : String = ""
var userIsTypingRef: FIRDatabaseReference!
var usersTypingQuery: FIRDatabaseQuery!
private var localTyping = false
var isTyping: Bool {
get {
return localTyping
}
set {
localTyping = newValue
userIsTypingRef.setValue(newValue)
}
}
override func viewDidLoad() {
super.viewDidLoad()
title = "Now Chatting With: " + userToBeChatted
setupBubbles()
// No avatars
collectionView!.collectionViewLayout.incomingAvatarViewSize = CGSizeZero
collectionView!.collectionViewLayout.outgoingAvatarViewSize = CGSizeZero
messageReference = rootReference.child("messages")
dataBaseMessageRef = messageReference.child("\(userToBeChatted)" + "\(FIRAuth.auth()?.currentUser?.displayName)")
print ("This users being messaged is: ", userToBeChatted)
}
override func didPressSendButton(button: UIButton!, withMessageText text: String!, senderId: String!,
senderDisplayName: String!, date: NSDate!) {
let itemRef = dataBaseMessageRef.childByAutoId() // 1
let messageItem = [ // 2
"text": text,
"senderId": senderId,
"receiver" : userToBeChatted,
"senderName": FIRAuth.auth()?.currentUser?.displayName,
"receiverID": userContacedID
]
itemRef.setValue(messageItem) // 3
// 4
JSQSystemSoundPlayer.jsq_playMessageSentSound()
// 5
finishSendingMessage()
}
override func viewDidAppear(animated: Bool) {
super.viewDidAppear(animated)
observeMessages()
observeTyping()
}
override func viewDidDisappear(animated: Bool) {
super.viewDidDisappear(animated)
}
override func collectionView(collectionView: JSQMessagesCollectionView!,
messageDataForItemAtIndexPath indexPath: NSIndexPath!) -> JSQMessageData! {
return messages[indexPath.item]
}
override func collectionView(collectionView: UICollectionView,
numberOfItemsInSection section: Int) -> Int {
return messages.count
}
override func collectionView(collectionView: JSQMessagesCollectionView!,
messageBubbleImageDataForItemAtIndexPath indexPath: NSIndexPath!) -> JSQMessageBubbleImageDataSource! {
let message = messages[indexPath.item] // 1
if message.senderId == senderId { // 2
return outgoingBubbleImageView
} else { // 3
return incomingBubbleImageView
}
}
override func collectionView(collectionView: JSQMessagesCollectionView!,
avatarImageDataForItemAtIndexPath indexPath: NSIndexPath!) -> JSQMessageAvatarImageDataSource! {
return nil
}
private func setupBubbles() {
let factory = JSQMessagesBubbleImageFactory()
outgoingBubbleImageView = factory.outgoingMessagesBubbleImageWithColor(
UIColor.jsq_messageBubbleBlueColor())
incomingBubbleImageView = factory.incomingMessagesBubbleImageWithColor(
UIColor.jsq_messageBubbleRedColor())
}
func addMessage(id: String, text: String) {
let message = JSQMessage(senderId: id, displayName: FIRAuth.auth()?.currentUser?.displayName , text: text)
messages.append(message)
}
override func collectionView(collectionView: UICollectionView,
cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
let cell = super.collectionView(collectionView, cellForItemAtIndexPath: indexPath)
as! JSQMessagesCollectionViewCell
let message = messages[indexPath.item]
if message.senderId == senderId {
cell.textView!.textColor = UIColor.whiteColor()
} else {
cell.textView!.textColor = UIColor.whiteColor()
}
return cell
}
private func observeMessages() {
dataBaseMessageRef = messageReference.child("\(userToBeChatted)\(FIRAuth.auth()?.currentUser?.displayName as String!)")
let messagesQuery = dataBaseMessageRef.queryLimitedToLast(25)
messagesQuery.observeEventType(.ChildAdded, withBlock: { snapshot in
let id = snapshot.value!["senderId"] as! String
let text = snapshot.value!["text"] as! String
self.addMessage(id, text: text)
self.finishReceivingMessage()
})
}
override func textViewDidChange(textView: UITextView) {
super.textViewDidChange(textView)
isTyping = textView.text != ""
}
private func observeTyping() {
let typingIndicatorRef = rootReference.child("typingIndicator")
userIsTypingRef = typingIndicatorRef.child(senderId)
userIsTypingRef.onDisconnectRemoveValue()
usersTypingQuery = typingIndicatorRef.queryOrderedByValue().queryEqualToValue(true)
usersTypingQuery.observeEventType(.Value, withBlock: { snapshot in
// You're the only one typing, don't show the indicator
if snapshot.childrenCount == 1 && self.isTyping { return }
// Are there others typing?
self.showTypingIndicator = snapshot.childrenCount > 0
self.scrollToBottomAnimated(true)
})
}
}
in viewDidAppear before observeMessages() insert messages.removeAll() or messages = []
Move observeMessages() from viewDidAppear() and place it in viewDidLoad().
Had the same problem and managed to fix it with the above.
I'm new to swift :D, and developing a simple chatting application using the JSQMessagesViewController. I read & followed JSQMessagesViewController sample project (https://www.syncano.io/blog/create-ios-chat-app-part1/) but my code occurs an error.
class ChatRoomViewController: JSQMessagesViewController {
let incomingBubble = JSQMessagesBubbleImageFactory().incomingMessagesBubbleImageWithColor(UIColor(red: 10/255, green: 180/255, blue: 230/255, alpha: 1.0))
let outgoingBubble = JSQMessagesBubbleImageFactory().outgoingMessagesBubbleImageWithColor(UIColor.lightGrayColor())
var messages = [JSQMessage]()
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
self.setup()
self.addDemoMessages()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func reloadMessagesView() {
self.collectionView?.reloadData()
}
func gotoReserve() {
let nextViewController = ReserveViewController(nibName: "ReserveViewController", bundle: nil)
self.navigationController!.pushViewController(nextViewController, animated: true)
}
}
//MARK - Setup
extension ChatRoomViewController {
func addDemoMessages() {
let message = JSQMessage(senderId: "zzz", displayName: "aaa", text: "asasd")
self.messages.append(message)
self.reloadMessagesView()
}
func setup() {
self.senderId = "user"
self.senderDisplayName = "user"
}
}
//MARK - Data Source
extension ChatRoomViewController {
override func collectionView(collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return self.messages.count
}
override func collectionView(collectionView: JSQMessagesCollectionView!, messageDataForItemAtIndexPath indexPath: NSIndexPath!) -> JSQMessageData! {
let data = self.messages[indexPath.row]
return data
}
override func collectionView(collectionView: JSQMessagesCollectionView!, didDeleteMessageAtIndexPath indexPath: NSIndexPath!) {
self.messages.removeAtIndex(indexPath.row)
}
override func collectionView(collectionView: JSQMessagesCollectionView!, messageBubbleImageDataForItemAtIndexPath indexPath: NSIndexPath!) -> JSQMessageBubbleImageDataSource! {
let data = messages[indexPath.row]
switch(data.senderId) {
case self.senderId:
return self.outgoingBubble
default:
return self.incomingBubble
}
}
override func collectionView(collectionView: JSQMessagesCollectionView!, avatarImageDataForItemAtIndexPath indexPath: NSIndexPath!) -> JSQMessageAvatarImageDataSource! {
return nil
}
}
//MARK - Toolbar
extension ChatRoomViewController {
override func didPressSendButton(button: UIButton!, withMessageText text: String!, senderId: String!, senderDisplayName: String!, date: NSDate!) {
let message = JSQMessage(senderId: senderId, senderDisplayName: senderDisplayName, date: date, text: text)
self.messages += [message]
self.finishSendingMessage()
}
override func didPressAccessoryButton(sender: UIButton!) {
}
}
When I run it,
the error message say
*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[JSQMessage messageHash]: unrecognized selector sent to instance 0x7fdf0a6e1f60'
and the app is terminated.
But it runs well after erasing
self.addDemoMessages()
code in viewDidLoad(). So I guess this code occurs error, but I don't know how to fix :( How can I fix it?
I had a similar problem with this when I subclassed the JSQMessage object. If you are doing that you just need to make sure that you implement the has for the message data. I just had to add this method to my message object
func messageHash() -> UInt {
return UInt(self.hash)
}
Hope that helps 👻
Here is my case,
to solve it by
Add -all_load to the other linker flags in your build settings.
-all_load forces the linker to load all object files from every archive it sees, even those without Objective-C code.
and
-force_load is available in Xcode 3.2 and later. It allows finer grain control of archive loading.
Each -force_load option must be followed by a path to an archive, and every object file in that archive will be loaded.
I can fetch the image from a url and able to display the image in a UIImageView in my DetailViewController. I would like to display the same image from this URL as a thumbnail in my tableviewcell.
My viewDidLoad
override func viewDidLoad() {
super.viewDidLoad()
self.UrlField.text = contact.Imageurl
let urlString = UrlField.text
loadImageView(urlString)
}
func textFieldShouldReturn(textField: UITextField) -> Bool {
let urlString = UrlField.text
loadImageView(urlString)
textField.resignFirstResponder()
return true
}
In this function I try to fetch the image from the URL
func loadImageView(url : String){
self.contact.Imageurl = url
self.contact.data = nil
let DatatoImage: (NSData?) -> Void = {
if let d = $0 {
let image = UIImage(data: d)
self.imageView.image = image
}else{
self.imageView.image = nil
}
}
if let d = contact.data {
DatatoImage(d)
} else {
contact.loadImage(DatatoImage)
}
}
In my cellForRowAtIndexPath I managed to load an image that I have hardcoded in my folder and named it as "images1.jpeg"
cell.imageView?.image = UIImage (named: "images1.jpeg", inBundle: nil, compatibleWithTraitCollection: nil)
MainViewController
import UIKit
class MasterTableViewController: UITableViewController, ContactDetailTableViewControllerDelegate {
var contacts: [ContactListEntry] = []
var currentContact: ContactListEntry!
var detailObject: ContactDetailTableViewController!
override func viewDidLoad() {
super.viewDidLoad()
// Uncomment the following line to preserve selection between presentations
// self.clearsSelectionOnViewWillAppear = false
// Uncomment the following line to display an Edit button in the navigation bar for this view controller.
// self.navigationItem.rightBarButtonItem = self.editButtonItem()
}
#IBAction func addContact(sender: UIBarButtonItem) {
currentContact = ContactListEntry(firstName: "", lastName: "", address: "", Imageurl: "")
contacts.append(currentContact)
performSegueWithIdentifier("showDetail", sender: self)
}
/* override func viewWillAppear(animated: Bool) {
if self.currentContact == nil || self.currentContact.isEmpty()
{
if count(contacts) > 0
{
contacts.removeLast()
}
}
tableView.reloadData()
}*/
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
// MARK: - Table view data source
/*override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
// #warning Potentially incomplete method implementation.
// Return the number of sections.
return 1
}*/
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
// #warning Incomplete method implementation.
// Return the number of rows in the section.
return contacts.count
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("contactcell", forIndexPath: indexPath) as! UITableViewCell
let contact = contacts[indexPath.row]
cell.textLabel?.text = "\(contact.firstName) \(contact.lastName)"
cell.imageView?.image = UIImage (named: "images1.jpeg", inBundle: nil, compatibleWithTraitCollection: nil)
let url = NSURL(string: "<# place your URL here #>")
return cell
}
/*
// Override to support conditional editing of the table view.
override func tableView(tableView: UITableView, canEditRowAtIndexPath indexPath: NSIndexPath) -> Bool {
// Return NO if you do not want the specified item to be editable.
return true
}
*/
// Override to support editing the table view.
override func tableView(tableView: UITableView, commitEditingStyle editingStyle: UITableViewCellEditingStyle, forRowAtIndexPath indexPath: NSIndexPath) {
if editingStyle == .Delete {
// Delete the row from the data source
tableView.deleteRowsAtIndexPaths([indexPath], withRowAnimation: .Fade)
} else if editingStyle == .Insert {
// Create a new instance of the appropriate class, insert it into the array, and add a new row to the table view
}
}
/*
// Override to support rearranging the table view.
override func tableView(tableView: UITableView, moveRowAtIndexPath fromIndexPath: NSIndexPath, toIndexPath: NSIndexPath) {
}
*/
/*
// Override to support conditional rearranging of the table view.
override func tableView(tableView: UITableView, canMoveRowAtIndexPath indexPath: NSIndexPath) -> Bool {
// Return NO if you do not want the item to be re-orderable.
return true
}
*/
/*
// MARK: - Navigation
// In a storyboard-based application, you will often want to do a little preparation before navigation
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
// Get the new view controller using [segue destinationViewController].
// Pass the selected object to the new view controller.
}
*/
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if let cell = sender as? UITableViewCell
{
cell.accessoryType = UITableViewCellAccessoryType.DisclosureIndicator
if (segue.identifier == "showDetail")
{
if let dvc = segue.destinationViewController as? ContactDetailTableViewController{
let indexPath = tableView.indexPathForCell(cell)!
currentContact = contacts[indexPath.row]
dvc.contact = currentContact
}}}
if let dvc = segue.destinationViewController as? ContactDetailTableViewController
{
dvc.contact = currentContact
dvc.delegate = self
}
}
func masterViewController(dvc: ContactDetailTableViewController, didUpdate contact: Person)
{
dvc.contact = currentContact
dvc.delegate = self
dvc.dismissViewControllerAnimated(true, completion: nil)
navigationController?.popToViewController(self, animated: true)
tableView.reloadData()
}
override func viewDidAppear(animated: Bool) {
tableView.reloadData()
}
}
/* Create our configuration first In view did load */
let configuration =
NSURLSessionConfiguration.defaultSessionConfiguration()
configuration.timeoutIntervalForRequest = 15.0
configuration.URLCache=NSURLCache(memoryCapacity: 4*1024*1024, diskCapacity: 20*1024*1024, diskPath: "CustomName"))
configuration.requestCachePolicy=NSURLRequestUseProtocolCachePolicy;
/* Now create our session which will allow us to create the tasks */
var session: NSURLSession!
session = NSURLSession(configuration: configuration,
delegate: self,
delegateQueue: nil)
/* Now attempt to download the contents of the URL in tableView cellForRowAtIndexpath */
let url = NSURL(string: "<# place your URL here #>")
task=session.dataTaskWithRequest(url!, completionHandler: { (NSData!, NSURLResponse!, NSError!) -> Void in
cell.imageView.image=UIImage(data: NSData))
})
task.start()
You can also set the cache,so that next tym when the request is fired then it is called from cache