IPhoneのすべての連絡先のリストを取得したい。
私はチェックした Address Book
参照、私は何かを見逃したかもしれませんが、連絡先のリストを取得する方法を提供するのを見ませんでした。
おそらくABPerson
関数 ABAddressBookCopyArrayOfAllPeople はそうでしょうか?
例 :
ABAddressBookRef addressBook = ABAddressBookCreate( );
CFArrayRef allPeople = ABAddressBookCopyArrayOfAllPeople( addressBook );
CFIndex nPeople = ABAddressBookGetPersonCount( addressBook );
for ( int i = 0; i < nPeople; i++ )
{
ABRecordRef ref = CFArrayGetValueAtIndex( allPeople, i );
...
}
私の最初の回答では、この回答の最後に、9.0より前のiOSバージョンで連絡先を取得する方法を示します。ここでは、他の回答に伴ういくつかの問題に対処します。
ただし、iOS 9以降のみをサポートする場合は、Contacts
フレームワークを使用して、古いAddressBook
フレームワークを使用するときに伴う厄介なブリッジングの問題を回避する必要があります。
したがって、iOS 9では、Contacts
フレームワークを使用します。
@import Contacts;
また、Info.plist
を更新し、NSContactsUsageDescription
を追加して、アプリが連絡先へのアクセスを必要とする理由を説明する必要があります。
そして、次のようなことをします:
CNAuthorizationStatus status = [CNContactStore authorizationStatusForEntityType:CNEntityTypeContacts];
if (status == CNAuthorizationStatusDenied || status == CNAuthorizationStatusRestricted) {
UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"Access to contacts." message:@"This app requires access to contacts because ..." preferredStyle:UIAlertControllerStyleActionSheet];
[alert addAction:[UIAlertAction actionWithTitle:@"Go to Settings" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
[[UIApplication sharedApplication] openURL:[NSURL URLWithString:UIApplicationOpenSettingsURLString] options:@{} completionHandler:nil];
}]];
[alert addAction:[UIAlertAction actionWithTitle:@"Cancel" style:UIAlertActionStyleCancel handler:nil]];
[self presentViewController:alert animated:TRUE completion:nil];
return;
}
CNContactStore *store = [[CNContactStore alloc] init];
[store requestAccessForEntityType:CNEntityTypeContacts completionHandler:^(BOOL granted, NSError * _Nullable error) {
// make sure the user granted us access
if (!granted) {
dispatch_async(dispatch_get_main_queue(), ^{
// user didn't grant access;
// so, again, tell user here why app needs permissions in order to do it's job;
// this is dispatched to the main queue because this request could be running on background thread
});
return;
}
// build array of contacts
NSMutableArray *contacts = [NSMutableArray array];
NSError *fetchError;
CNContactFetchRequest *request = [[CNContactFetchRequest alloc] initWithKeysToFetch:@[CNContactIdentifierKey, [CNContactFormatter descriptorForRequiredKeysForStyle:CNContactFormatterStyleFullName]]];
BOOL success = [store enumerateContactsWithFetchRequest:request error:&fetchError usingBlock:^(CNContact *contact, BOOL *stop) {
[contacts addObject:contact];
}];
if (!success) {
NSLog(@"error = %@", fetchError);
}
// you can now do something with the list of contacts, for example, to show the names
CNContactFormatter *formatter = [[CNContactFormatter alloc] init];
for (CNContact *contact in contacts) {
NSString *string = [formatter stringFromContact:contact];
NSLog(@"contact = %@", string);
}
}];
以下は、iOS 9.0より前のiOSバージョンをサポートする場合に適用可能な私の答えです。
-
あなたの質問だけでなく、ここに記載されている多くの回答に対するいくつかの反応(許可のリクエストに失敗する、ABAddressBookCreateWithOptions
エラーを適切に処理しない、またはリークする):
明らかに、AddressBook
フレームワークをインポートします。
#import <AddressBook/AddressBook.h>
または
@import AddressBook;
アプリが連絡先にアクセスするための許可をリクエストする必要があります。例えば:
ABAuthorizationStatus status = ABAddressBookGetAuthorizationStatus();
if (status == kABAuthorizationStatusDenied || status == kABAuthorizationStatusRestricted) {
// if you got here, user had previously denied/revoked permission for your
// app to access the contacts and all you can do is handle this gracefully,
// perhaps telling the user that they have to go to settings to grant access
// to contacts
[[[UIAlertView alloc] initWithTitle:nil message:@"This app requires access to your contacts to function properly. Please visit to the \"Privacy\" section in the iPhone Settings app." delegate:nil cancelButtonTitle:@"OK" otherButtonTitles:nil] show];
return;
}
CFErrorRef error = NULL;
ABAddressBookRef addressBook = ABAddressBookCreateWithOptions(NULL, &error);
if (!addressBook) {
NSLog(@"ABAddressBookCreateWithOptions error: %@", CFBridgingRelease(error));
return;
}
ABAddressBookRequestAccessWithCompletion(addressBook, ^(bool granted, CFErrorRef error) {
if (error) {
NSLog(@"ABAddressBookRequestAccessWithCompletion error: %@", CFBridgingRelease(error));
}
if (granted) {
// if they gave you permission, then just carry on
[self listPeopleInAddressBook:addressBook];
} else {
// however, if they didn't give you permission, handle it gracefully, for example...
dispatch_async(dispatch_get_main_queue(), ^{
// BTW, this is not on the main thread, so dispatch UI updates back to the main queue
[[[UIAlertView alloc] initWithTitle:nil message:@"This app requires access to your contacts to function properly. Please visit to the \"Privacy\" section in the iPhone Settings app." delegate:nil cancelButtonTitle:@"OK" otherButtonTitles:nil] show];
});
}
CFRelease(addressBook);
});
上記では、他の人が提案したパターンを使用していないことに注意してください。
CFErrorRef *error = NULL;
ABAddressBookRef addressBook = ABAddressBookCreateWithOptions(NULL, error);
それは正しくありません。上記のように、次のことが必要です。
CFErrorRef error = NULL;
ABAddressBookRef addressBook = ABAddressBookCreateWithOptions(NULL, &error);
前者のパターンはエラーを正しくキャプチャしませんが、後者はキャプチャします。 error
がNULL
でなかった場合、CFRelease
を忘れないでください(または、所有権をARCに移しました)。
連絡先を反復するには、次のことを行います。
- (void)listPeopleInAddressBook:(ABAddressBookRef)addressBook
{
NSArray *allPeople = CFBridgingRelease(ABAddressBookCopyArrayOfAllPeople(addressBook));
NSInteger numberOfPeople = [allPeople count];
for (NSInteger i = 0; i < numberOfPeople; i++) {
ABRecordRef person = (__bridge ABRecordRef)allPeople[i];
NSString *firstName = CFBridgingRelease(ABRecordCopyValue(person, kABPersonFirstNameProperty));
NSString *lastName = CFBridgingRelease(ABRecordCopyValue(person, kABPersonLastNameProperty));
NSLog(@"Name:%@ %@", firstName, lastName);
ABMultiValueRef phoneNumbers = ABRecordCopyValue(person, kABPersonPhoneProperty);
CFIndex numberOfPhoneNumbers = ABMultiValueGetCount(phoneNumbers);
for (CFIndex j = 0; j < numberOfPhoneNumbers; j++) {
NSString *phoneNumber = CFBridgingRelease(ABMultiValueCopyValueAtIndex(phoneNumbers, j));
NSLog(@" phone:%@", phoneNumber);
}
CFRelease(phoneNumbers);
NSLog(@"=============================================");
}
}
かなり重要な詳細、つまり "Create Rule" に注意を向けたいと思います。
Core Foundation関数には、返されたオブジェクトをいつ所有するかを示す名前があります。
名前に「
Create
」が埋め込まれているオブジェクト作成関数。名前に「
Copy
」が埋め込まれているオブジェクト複製関数。オブジェクトを所有している場合、それを終了したときに所有権を放棄するのはあなたの責任です(CFReleaseを使用)。
これは、名前にCreate
またはCopy
を含むCore Foundation関数によって返されたオブジェクトを解放する責任があることを意味します。 CFRelease
を明示的に呼び出すことができます(上記でaddressBook
とphoneNumbers
で行ったように)、またはフリーダイヤルブリッジングをサポートするオブジェクトの場合、__bridge_transfer
で所有権をARCに転送できますまたはCFBridgingRelease
(上記でallPeople
、lastName
、firstName
、およびphoneNumber
で行ったように)。
静的アナライザー(押す shift+command+B Xcodeで選択するか、[製品]メニューから[分析]を選択します)は、この「ルールの作成」を怠り、適切なオブジェクトのリリースに失敗した多くの状況を識別できます。そのため、このようなCore Foundationコードを作成するときは、常に静的アナライザーで実行して、明らかなリークがないことを確認してください。
このコードを使用して、すべての名前+姓+電話番号を表示します(iOS 6)。シミュレーターでも動作します:
CFErrorRef *error = NULL;
ABAddressBookRef addressBook = ABAddressBookCreateWithOptions(NULL, error);
CFArrayRef allPeople = ABAddressBookCopyArrayOfAllPeople(addressBook);
CFIndex numberOfPeople = ABAddressBookGetPersonCount(addressBook);
for(int i = 0; i < numberOfPeople; i++) {
ABRecordRef person = CFArrayGetValueAtIndex( allPeople, i );
NSString *firstName = (__bridge NSString *)(ABRecordCopyValue(person, kABPersonFirstNameProperty));
NSString *lastName = (__bridge NSString *)(ABRecordCopyValue(person, kABPersonLastNameProperty));
NSLog(@"Name:%@ %@", firstName, lastName);
ABMultiValueRef phoneNumbers = ABRecordCopyValue(person, kABPersonPhoneProperty);
for (CFIndex i = 0; i < ABMultiValueGetCount(phoneNumbers); i++) {
NSString *phoneNumber = (__bridge_transfer NSString *) ABMultiValueCopyValueAtIndex(phoneNumbers, i);
NSLog(@"phone:%@", phoneNumber);
}
NSLog(@"=============================================");
}
適切なインポートがあることを確認してください
#import <AddressBook/AddressBook.h>
次に、すべての連絡先を使用してCFArrayオブジェクトを取得できます
CFArrayRef ABAddressBookCopyArrayOfAllPeople (ABAddressBookRef addressBook);
IOS 6では、ABAddressBookCreateWithOptions
の更新バージョンであるABAddressBookCreate
を使用してください。
CFErrorRef * error = NULL;
ABAddressBookRef addressBook = ABAddressBookCreateWithOptions(NULL, error);
CFArrayRef allPeople = ABAddressBookCopyArrayOfAllPeople(addressBook);
CFIndex numberOfPeople = ABAddressBookGetPersonCount(addressBook);
for(int i = 0; i < numberOfPeople; i++){
ABRecordRef person = CFArrayGetValueAtIndex( allPeople, i );
// More code here
}
更新 for iOS 9.0
。 AppleはAddressBook
を廃止し、今ではContacts
フレームワークを追加しました:
CNContactStore
プロパティを追加し、次のように定義します。
self.contactsStrore = [[CNContactStore alloc] init];
次に、これらのメソッドを追加して、すべての連絡先を読み取ります。
-(void)checkContactsAccess{
[self requestContactsAccessWithHandler:^(BOOL grandted) {
if (grandted) {
CNContactFetchRequest *request = [[CNContactFetchRequest alloc] initWithKeysToFetch:@[CNContactFamilyNameKey, CNContactGivenNameKey, CNContactNamePrefixKey, CNContactMiddleNameKey, CNContactPhoneNumbersKey]];
[self.contactsStrore enumerateContactsWithFetchRequest:request error:nil usingBlock:^(CNContact * _Nonnull contact, BOOL * _Nonnull stop) {
NSLog(@"%@", contact.familyName);
NSLog(@"%@", contact.givenName);
NSLog(@"%@", contact.namePrefix);
NSLog(@"%@", contact.middleName);
NSLog(@"%@", contact.phoneNumbers);
NSLog(@"=============================================");
}];
}
}];
}
-(void)requestContactsAccessWithHandler:(void (^)(BOOL grandted))handler{
switch ([CNContactStore authorizationStatusForEntityType:CNEntityTypeContacts]) {
case CNAuthorizationStatusAuthorized:
handler(YES);
break;
case CNAuthorizationStatusDenied:
case CNAuthorizationStatusNotDetermined:{
[self.contactsStrore requestAccessForEntityType:CNEntityTypeContacts completionHandler:^(BOOL granted, NSError * _Nullable error) {
handler(granted);
}];
break;
}
case CNAuthorizationStatusRestricted:
handler(NO);
break;
}
}
IOS 9.0より前=> AddressBook
フレームワークを使用します。まずアクセスを確認し、ユーザーの連絡先へのアクセスをリクエストする必要があります。
// Prompt the user for access to their Address Book data
-(void)requestAddressBookAccess
{
YourViewController * __weak weakSelf = self;
ABAddressBookRequestAccessWithCompletion(self.addressBook, ^(bool granted, CFErrorRef error)
{
if (granted)
{
dispatch_async(dispatch_get_main_queue(), ^{
[weakSelf accessGrantedForAddressBook];
});
}
});
}
-(void)checkAddressBookAccess
{
switch (ABAddressBookGetAuthorizationStatus())
{
// Update our UI if the user has granted access to their Contacts
case kABAuthorizationStatusAuthorized:
[self accessGrantedForAddressBook];
break;
// Prompt the user for access to Contacts if there is no definitive answer
case kABAuthorizationStatusNotDetermined :
[self requestAddressBookAccess];
break;
// Display a message if the user has denied or restricted access to Contacts
case kABAuthorizationStatusDenied:
case kABAuthorizationStatusRestricted:
{
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Privacy Warning"
message:@"Permission was not granted for Contacts."
delegate:nil
cancelButtonTitle:@"OK"
otherButtonTitles:nil];
[alert show];
}
break;
default:
break;
}
}
Maheshとwzbozonのおかげで、次のコードが役に立ちました。
CFErrorRef * error = NULL;
addressBook = ABAddressBookCreateWithOptions(NULL, error);
ABAddressBookRequestAccessWithCompletion(addressBook, ^(bool granted, CFErrorRef error)
{
if (granted)
{
dispatch_async(dispatch_get_main_queue(), ^{
CFArrayRef allPeople = ABAddressBookCopyArrayOfAllPeople(addressBook);
CFIndex numberOfPeople = ABAddressBookGetPersonCount(addressBook);
for(int i = 0; i < numberOfPeople; i++){
ABRecordRef person = CFArrayGetValueAtIndex( allPeople, i );
NSString *firstName = (__bridge NSString *)(ABRecordCopyValue(person, kABPersonFirstNameProperty));
NSString *lastName = (__bridge NSString *)(ABRecordCopyValue(person, kABPersonLastNameProperty));
NSLog(@"Name:%@ %@", firstName, lastName);
ABMultiValueRef phoneNumbers = ABRecordCopyValue(person, kABPersonPhoneProperty);
NSMutableArray *numbers = [NSMutableArray array];
for (CFIndex i = 0; i < ABMultiValueGetCount(phoneNumbers); i++) {
NSString *phoneNumber = (__bridge_transfer NSString *) ABMultiValueCopyValueAtIndex(phoneNumbers, i);
[numbers addObject:phoneNumber];
}
NSMutableDictionary *contact = [NSMutableDictionary dictionary];
[contact setObject:name forKey:@"name"];
[contact setObject:numbers forKey:@"numbers"];
[all_contacts addObject:contact];
}
});
}
});
Swiftバージョン:
override func viewDidLoad() {
super.viewDidLoad()
var error: Unmanaged<CFErrorRef>?
var addressBook: ABAddressBook = ABAddressBookCreateWithOptions(nil, &error).takeRetainedValue()
if ABAddressBookGetAuthorizationStatus() == ABAuthorizationStatus.NotDetermined {
ABAddressBookRequestAccessWithCompletion(addressBook, {
(granted:Bool, error:CFErrorRef!) -> Void in
self.populateFrom(addressBook: addressBook)
})
}
else if ABAddressBookGetAuthorizationStatus() == ABAuthorizationStatus.Authorized {
self.populateFrom(addressBook: addressBook)
}
}
func populateFrom(#addressBook:ABAddressBook){
let allPeople = ABAddressBookCopyArrayOfAllPeople(addressBook).takeRetainedValue()
let nPeople = ABAddressBookGetPersonCount(addressBook)
for index in 0..<nPeople{
let person: ABRecordRef = Unmanaged<ABRecordRef>.fromOpaque(COpaquePointer(CFArrayGetValueAtIndex(allPeople, index))).takeUnretainedValue()
let firstName: String = ABRecordCopyValue(person, kABPersonFirstNameProperty).takeUnretainedValue() as? String
println("\(firstName.debugDescription)")
}
}
チェックアウト https://github.com/heardrwt/RHAddressBook (254つ星01/2014)。
はるかに単純なAPIでAddressBookのObjCラッパーを提供します。
これはios 7およびios 8で機能します。
NSMutableArray *result = [[NSMutableArray alloc] init];
CFErrorRef *error = nil;
ABAddressBookRef addressBook = ABAddressBookCreateWithOptions(NULL, error);
__block BOOL accessGranted = NO;
if (ABAddressBookRequestAccessWithCompletion != NULL){
dispatch_semaphore_t sema = dispatch_semaphore_create(0);
ABAddressBookRequestAccessWithCompletion(addressBook, ^(bool granted, CFErrorRef error) {
accessGranted = granted;
dispatch_semaphore_signal(sema);
});
dispatch_semaphore_wait(sema, DISPATCH_TIME_FOREVER);
}
else{
accessGranted = YES;
}
if (accessGranted){
// If the app is authorized to access the first time then add the contact
ABAddressBookRef addressBook = ABAddressBookCreateWithOptions(NULL, error);
CFArrayRef allPeople = ABAddressBookCopyArrayOfAllPeople(addressBook);
CFIndex numberOfPeople = ABAddressBookGetPersonCount(addressBook);
for (int i=0; i<numberOfPeople; i++){
CFStringRef phone;
ABRecordRef person = CFArrayGetValueAtIndex(allPeople, i);
CFStringRef firstName = ABRecordCopyValue(person, kABPersonFirstNameProperty);
CFStringRef lastName = ABRecordCopyValue(person, kABPersonLastNameProperty);
NSString *userName = @"NoName";
userName = [NSString stringWithFormat:@"%@ %@", firstName, lastName];
userName = [userName stringByReplacingOccurrencesOfString:@"(null)" withString:@""];
ABMutableMultiValueRef phoneNumbers = ABRecordCopyValue(person, kABPersonPhoneProperty);
CFIndex phoneNumberCount = ABMultiValueGetCount( phoneNumbers );
phone = nil;
for ( CFIndex ind= 0; ind<phoneNumberCount; ind++ ){
CFStringRef phoneNumberLabel = ABMultiValueCopyLabelAtIndex( phoneNumbers, ind);
CFStringRef phoneNumberValue = ABMultiValueCopyValueAtIndex( phoneNumbers, ind);
// converts "_$!<Work>!$_" to "work" and "_$!<Mobile>!$_" to "mobile"
// Find the ones you want here
if (phoneNumberLabel != nil){
NSStringCompareOptions compareOptions = NSCaseInsensitiveSearch;
if(CFStringCompare(phoneNumberLabel, CFSTR("mobile"),compareOptions)){
phone = phoneNumberValue;
}
phone = phoneNumberValue;
NSStringCompareOptions compareOptionss = NSCaseInsensitiveSearch;
if(!CFStringCompare(phone, CFSTR("1-800-MY-Apple"),compareOptionss)){
continue;
}
NSMutableArray *theKeys = [NSMutableArray arrayWithObjects:@"name", @"small_name",@"phone", @"checked", nil];
NSMutableArray *theObjects = [NSMutableArray arrayWithObjects:userName, [userName lowercaseString],phone, @"NO", nil];
NSMutableDictionary *theDict = [NSMutableDictionary dictionaryWithObjects:theObjects forKeys:theKeys];
if (![[functions formatNumber:(__bridge NSString *)(phone)] isEqualToString:[[NSUserDefaults standardUserDefaults]valueForKey:@"phoneNumber"]]){
[result addObject:theDict];
}
}
}
}
}
//sort array
NSSortDescriptor * descriptor = [[NSSortDescriptor alloc] initWithKey:@"small_name"
ascending:YES]; // 1
NSArray * sortedArray = [result sortedArrayUsingDescriptors:[NSArray arrayWithObject:descriptor]];
アルファベット順に並べ替える場合は、以下のコードを使用できます。
CFErrorRef *error = NULL;
ABAddressBookRef addressBook = ABAddressBookCreateWithOptions(NULL, error);
CFArrayRef allPeople = ABAddressBookCopyArrayOfAllPeople(addressBook);
CFIndex numberOfPeople = ABAddressBookGetPersonCount(addressBook);
CFMutableArrayRef peopleMutable = CFArrayCreateMutableCopy(kCFAllocatorDefault,
CFArrayGetCount(allPeople),
allPeople);
CFArraySortValues(peopleMutable,
CFRangeMake(0, CFArrayGetCount(peopleMutable)),
(CFComparatorFunction) ABPersonComparePeopleByName,
kABPersonSortByFirstName);
ABAddressBookRef addressBook = ABAddressBookCreate( );
CFArrayRef allPeople = ABAddressBookCopyArrayOfAllPeople( addressBook );
CFIndex nPeople = ABAddressBookGetPersonCount( addressBook );
for ( int i = 0; i < nPeople; i++ )
{
ABRecordRef ref = CFArrayGetValueAtIndex( allPeople, i );
...
}
これは、すべての連絡先をテーブルビューで取得する完全なデモです。
import UIKit
import ContactsUI
import AddressBook
import Contacts
class ShowContactsVC: UIViewController,CNContactPickerDelegate,UITableViewDelegate,UITableViewDataSource
{
@IBOutlet weak var tableView: UITableView!
let peoplePicker = CNContactPickerViewController()
let appDelegate = UIApplication.sharedApplication().delegate as! AppDelegate
var contacts = [CNContact]()
var option : Int = 0
var userAccessGranted : Bool = false
var dataArray : NSMutableArray?
override func viewDidLoad()
{
super.viewDidLoad()
peoplePicker.delegate = self
self.checkIfUserAccessGranted()
self.tableView.delegate = self
self.tableView.dataSource = self
navigationController!.navigationBar.barTintColor = UIColor.grayColor()
if(self.userAccessGranted)
{
self.tableView.hidden = false
fetchContacts()
}
}
func numberOfSectionsInTableView(tableView: UITableView) -> Int
{
return 1
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int
{
if dataArray == nil {
return 0;
}
else{
return dataArray!.count
}
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell
{
let cell = tableView.dequeueReusableCellWithIdentifier("TableCell", forIndexPath: indexPath) as! ContactsTableViewCell
let data = dataArray![indexPath.row] as! Data;
cell.lblName.text = data.name
cell.imgContact.image = data.image
return cell
}
func tableView(tableView: UITableView, willDisplayCell cell: UITableViewCell, forRowAtIndexPath indexPath: NSIndexPath)
{
cell.backgroundColor = UIColor.cyanColor()
}
func checkIfUserAccessGranted()
{
appDelegate.requestForAccess { (accessGranted) -> Void in
if accessGranted {
self.userAccessGranted = true;
}else{
self.userAccessGranted = false;
}
}
}
func fetchContacts()
{
dataArray = NSMutableArray()
let toFetch = [CNContactGivenNameKey, CNContactImageDataKey, CNContactFamilyNameKey, CNContactImageDataAvailableKey]
let request = CNContactFetchRequest(keysToFetch: toFetch)
do{
try appDelegate.contactStore.enumerateContactsWithFetchRequest(request) {
contact, stop in
print(contact.givenName)
print(contact.familyName)
print(contact.identifier)
var userImage : UIImage;
// See if we can get image data
if let imageData = contact.imageData {
//If so create the image
userImage = UIImage(data: imageData)!
}else{
userImage = UIImage(named: "no_contact_image")!
}
let data = Data(name: contact.givenName, image: userImage)
self.dataArray?.addObject(data)
}
} catch let err{
print(err)
}
self.tableView.reloadData()
}
func contactPickerDidCancel(picker: CNContactPickerViewController)
{
picker.dismissViewControllerAnimated(true, completion: nil)
self.navigationController?.popToRootViewControllerAnimated(true)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
import UIKit
class Data {
let name : String
let image : UIImage
init(name : String, image : UIImage) {
self.image = image
self.name = name
}
}