رفتن به مطلب
جامعه‌ی برنامه‌نویسان مُدرن ایران

تمامی فعالیت ها

این جریان به طور خودکار بروزرسانی می شود     

  1. دیروز
  2. با سلام و عرض خسته نباشید. نظرتون راجع به پلتفرم vert.x چیست؟ به نظر میاد توی تست ها عملکرد خوبی داشته و در بسیاری موارد از فریمورک های c++ هم بهتر عمل کرده. ویژگی خوبش هم اینه که میشه با جاوا اسکریپت و روبی هم براش کد نوشت.
  3. هفته گذشته
  4. aderchox

    ضمن تشکر،لطفا یک مقاله هم درباره AutoMake بنویسید.
  5. جدیدا
  6. سلام و درود، مدتی است از سرویس‌های کاوه‌نگار جهت استفاده در پروژه‌‌های خودم استفاده می‌کنم و مطمئنم یکی از بهترین سرویس‌دهنده‌های ایرانی در زمینه‌ی پیام کوتاه است. متأسفانه همانطور که می‌دانید بسیاری از سرویس‌دهنده‌ها در ایران به خاطر عدم شناخت دقیق از اهمیت و کاربرد سی++ هیچ حرکتی در توسعه‌ی سرویس‌های خود در رابطه با سی++ را نمی‌کنند. بنابراین، جدیداً تصمیم گرفتم کیت‌های توسعه در قالب رابط‌های برنامه‌نویسی مورد نیاز رو برای این چنین شرکت و سرویس‌ها آن ارائه کنم. معرفی سرویس پیام کوتاه کاوه‌نگار کاوه نگار با ارائه وب‌سرویس پیامک و تماس صوتی پیشرفته برای توسعه دهندگان ،امکان ارسال و دریافت پیامک و برقراری تماس اینترنتی را در اغلب سرویس های نرم افزاری مهیا می کند. اهمیت وجود این سرویس در زبان‌هایی مانند C و ++C همانطور که می‌دانید با توجه به اهمیت این زبان‌ها و به خصوص پشتیبانی از کتابخانه‌های بسیار مدرن در توسعه‌ی اپلیکیشن‌ها و وب‌ها کاربرد بسیاری دارند که شاید در کشور ما آن‌چنان با آن‌ها آشنا نیستیم. بنابراین وجود سرویس‌های ارسال پیامک در قالب زبان‌ سی‌پلاس‌پلاس می‌تواند کمک بسیار بزرگی به توسعه‌دهندگان و علاقه‌مندان آن در حوزه‌های توسعه‌ی نرم‌افزار و انواع برنامه‌های موبایل و وب کمک کند. ساختار اولیه خروجی سرویس کاوه‌نگار به صورت زیر است: { "return": { "status":404, "message":"متد تعریف نشده است" }, "entries": { null } } در صورتی که مقادیر ارسالی صحیح و مطابق با اطلاعات کاربری موجود در کاوه‌نگار باشد نتیجه‌ی برگشتی آن به صورت زیر خواهد بود: { "return": { "status": 200, "message": "تایید شد" }, "entries": [ { "messageid": 8792343, "message": "خدمات پیام کوتاه کاوه نگار", "status": 1, "statustext": "در صف ارسال", "sender": "10004346", "receptor": "0914XXXXXXX", "date": 1356619709, "cost": 120 } ] } نمونه‌ی اولیه که توسعه داده شده، با مفهوم اولیه جهت ارسال پیام کوتاه بر اساس کلید و شماره‌های ارسالی آماده شده که کد نمونه‌ی آن به صورت زیر خواهد بود. #include <iostream> #include <Kavenegar> int main() { //! Your Api Key std::string apiKey {"Your Api-Key"}; //! Kavenegar Default Sender Number std::string senderLine {"10004346"}; Kavenegar::KavenegarApi api(MethodType ,"10004346",apiKey); //ToDo.. try catch exception handling. api.send("09140000000","Hi!"); std::cout << "Result : " << api.getResult(); //JSon Output return 0; } نکته: نمونه‌ی ساخته شده کامل و با تمام جزئیات موجود در کاوه‌نگار تکمیل و توسعه داده خواهد شد. لینک مربوط به کیت توسعه در گیت‌هاب. جهت استفاده از این نمونه توجه داشته باشید که جهت اجرای وب‌سرویس آن نیاز به نصب Curl و RapidJson خواهید داشت.
  7. با سلام و درود، همانطور که می‌دانید ویژگی‌های اخیر در استاندارد‌های ۱۷ و ۲۰ بسیار عظیم و کاربردی هستند. هدف ما در مرجع آی‌او‌استریم این است که با توجه به به‌روز‌رسانی‌های زبان سی‌پلاس‌پلاس مهمترین مواردی که نیاز است معرفی کنیم. بنابراین در این بخش به یکی از کاربردی‌ترین موارد مرتبط در استاندارد ۱۷ با عنوان صفت‌های ویژه اشاره می‌شود که در ادامه به تعریف هر یک از آن‌ها می‌پردازیم. با توجه به استاندارد‌های ۱۱ و ۱۴ که در آن صفت‌هایی همچون [[deprecated]] و [[noreturn]] معرفی شده‌اند که وظیفه‌ی آن به ترتیب نمایش وضعیت منسوخ شدن یک عملکرد و یا وضعیت بازگشتی یک تابع از نوع void است. چنین صفاتی می‌توانند در زمان اعلان و تعریف متغیر‌ها و یا توابع مورد استفاده قرار گیرند. به عنوان مثال اگر کدی به صورت زیر داشته باشیم: [[deprecated]] void print(const std::string &message) { std::cout << message << std::endl; } در صورتی که تابع print در بخشی از برنامه مورد استفاده قرار بگیرد، پیغامی از سمت کامپایلر از نوع اخطار (warning) ساطع می‌شود، مبنی بر آن که تابع مربوطه به عنوان منسوخ شده یاد شده است. warning: 'print' is deprecated این ویژگی می‌تواند در ساخت و توسعه‌ی کتابخانه‌ها، موتور‌ها، چهارچوب (فریم‌ورک‌) و برنامه‌هایی که قرار است دیگر برنامه‌نویسان از آن‌ها استفاده کنند بسیار می‌تواند کاربردی باشد؛ چرا که با اعمال چنین خاصیت‌هایی در کد‌های شما برای توسعه‌دهندگان یادآوری خواهد شد که کد مربوطه در نسخه‌ی جدید یا نسخه‌های بعدی امکان حذف و یا تغییر را خواهد داشت. #include <iostream> #include <string> [[deprecated]] void print(const std::string &message) { std::cout << message << std::endl; } int main() { print("Hello, World!"); return 0; } در مثال بالا اخطار پیش‌فرض از سمت کامپایلر ساطع می‌شود، اما در بعضی از مواقع لازم است پیغام سفارشی جهت راهنمایی بیشتر کاربر اعمال شود که در این صورت صفت می‌تواند پیغام از نوع رشته را دریافت و در هنگام ساطع شدن، آن را نمایش دهد. برای این کار کافی است متن مورد نظر را به صورت زیر در صفت خود تعیین کنیم. [[deprecated("Use printView with print instead, this function will be removed in the next release")]] برای مثال یک تابع جایگزین و بهینه شده را به صورت زیر در نظر بگیرید، کامپالر اخطار مروبطه و سفارشی شده را نسبت به آن ساطع خواهد کرد. #include <iostream> #include <string> [[deprecated]] void print(const std::string &message) { std::cout << message << std::endl; } void printView(std::string_view message) { std::cout << message << std::endl; } int main() { printView("Hello, World!"); return 0; } همچنین در رابطه با صفت [[noreturn]] که در استاندارد ۱۱ معرفی شده است، باید در نظر داشت این صفت جهت بهینه‌سازی کامپایلر در رابطه با تولید هشدار‌های بهتر و همچنین اعلام اینکه تابع مربوطه قابل دسترسی نیست مورد استفاده قرار می‌گیرد. مثال: #include <iostream> [[noreturn]] void myFunction() { std::cout << "Hello, World!" << std::endl; throw "error"; } void print() { std::cout << "Print Now!"; } int main() { myFunction(); print(); return 0; } در کد فوق، در زمان هم‌گردانی (کامپایل) پیغام‌ زیر ساطع می‌شود: warning: code will never be executed بنابراین در زمان اجرا تابع print(); اجرا نخواهد شد، زیرا به عنوان یک کد غیر قابل دسترس بعد از myFunction توسط کامپایلر یاد می‌شود. چرا که این امر اجازه می‌دهد تا کامپایلر بهینه‌سازی‌های مختلفی را انجام دهد - نیازی به ذخیره‌سازی‌ و بازیابی هرگونه حالت‌های ناپایدار در اطراف صدا زننده (Caller) نیست. بنابراین می‌تواند کد‌های غیر قابل دسترس را از بین ببرد. با توجه به نیاز‌های این چنینی، در استاندارد ۱۷ صفت‌های جدید‌تر و کاربردی‌تری نیز ارائه شده است که به معرفی هر یک از آن‌ها در بخش اول از این مقاله می‌پردازیم. صفت‌های معرفی شده در استاندارد 1z یا همان ۱۷ به صورت زیر هستند: [[fallthrough]] [[maybe_unused]] [[nodiscard]] معرفی صفت [[fallthrough]] به طور معمول در برنامه‌نویسی، هر وقت که مرحله‌ی مربوط به case در دستور switch به انتهای خود می‌رسد، کد مربوطِ به دستورِ case بعدی اجرا خواهد شد. طبیعتاً عبارت break می‌تواند از این امر جلوگیری کند. اما از آن‌جایی که این رفتار را به اصطلاح fall-through می‌شناسیم، ممکن است در صورت عدم معرفی اشکالاتی را فراهم کند، در این حالت چندین کامپایلر و ابزار‌های آنالیز کننده خطای مرتبط به آن را هشدار می‌دهند تا کاربر در جریان قرار بگیرد. با توجه به این موضوع که ممکن است بعضاً این مورد چشم‌ پوشی شود، در سی‌پلاس‌پلاس ۱۷ به بعد یک صفت استاندارد معرفی شد تا توسعه‌دهنده بتواند با قرار دادن آن در مکان سقوط (fall-through) به کامپایلر اعلام کند که هشداری در آن بخش لازم نیست. کامپایلر‌ها می‌توانند هشدارهای مطمئنی را در زمانی که یک عبارت case بدون اجرای دستور break به انتهای خود می‌رسند و یا سقوط (fall-through) می‌کند، حداقل با یک جمله‌ی مربوطِ به آن را ساطع کند. برای مثال به کد زیر توجه کنید: #include <iostream> int main() { int number { 2017 }; int standard = {0}; switch(number) { case 2011: case 2014: case 2017: std::cout << "Using modern C++" << std::endl; case 1998: case 2003: standard = number; } return 0; } در کد فوق، در زمان اجرای دستور case سوم با مقدار ۲۰۱۷، کامپایلر هشداری به صورت زیر را اعمال خواهد کرد. warning: unannotated fall-through between switch labels در این حالت برای از بین بردن (چشم‌پوشی کردن) از این خطا در صورتی که نیاز نباشد موارد دیگر مورد بررسی قرار بگیرد قرار دادن دستور break بعد از آن می‌تواند منطقی باشد. اما با توجه به انتظاری که می‌رود تا دستورات بدون توقف بین آن‌ها اجرا شود، قراردادن دستور [[fallthrough]]; بعد از آن می‌تواند راه حل بسیار مناسبی باشد. #include <iostream> int main() { int number { 2017 }; int standard = {0}; switch(number) { case 2011: case 2014: case 2017: std::cout << "Using modern C++" << std::endl; [[fallthrough]]; // > No warning case 1998: case 2003: standard = number; } return 0; } در این حالت، کامپایلر بدون ساطع کردن خطا آن را هم‌گردانی خواهد کرد. معرفی صفت [[maybe_unused]] صفت [[maybe_unused]] برای نشان دادن کد ایجاد شده‌ای است که ممکن است از منطق قطعی استفاده نکند. این مورد ممکن است اغلب در لینک شدن با پیش‌پردازنده‌ها مورد استفاده قرار بگیرد یا نگیرد. از آن‌جایی که کامپایلر (هم‌گردان‌ها) می‌توانند نسبت به متغیر‌های بلا استفاده هشدار ساطع کنند، این صفت روش بسیار خوبی برای سرکوب آن‌ها خواهد بود. استفاده از این ویژگی می‌تواند در بخش‌های مهمی مفید باشد، فرض کنید کتابخانه‌ای نوشته‌ایم که قرار است به صورت چند-سکویی دارای ویژگی‌های یکسان در بستر‌های مختلف باشد. برای مثال ساخت یک فایل در مسیر مشخصی از سیستم‌عامل مورد نظر جهت اعمال تنظیمات نرم‌افزار. namespace FileSystem::Configuration { [[maybe_unused]] std::string createWindowsConfigFilePath(const std::string &relativePath); [[maybe_unused]] std::string createMacOSConfigFilePath(const std::string &relativePath); [[maybe_unused]] std::string createLinuxConfigFilePath(const std::string &relativePath); [[maybe_unused]] std::string createiOSConfigFilePath(const std::string &relativePath); [[maybe_unused]] std::string createAndroidConfigFilePath(const std::string &relativePath); } به کد بالا توجه کنید، در صورتی که شما در محیط کد‌نویسی در حال استفاده از یک دستور مورد نظر از بین دستورات بالا هستید، طبیعتاً کامپایلر به بقیه‌ی دستوراتی که از آن‌ها استفاده نمی‌کنید پیغامی مبنی بر آن‌ که دستور مربوطه بلا‌استفاده مانده است را ساطع می‌کند. جهت جلو‌گیری از این هشدار‌ها کافی است صفت [[maybe_unused]] را قبل از آن‌ها اعمال کنید. معرفی صفت [[nodiscard]] در صورتی که از [[nodiscard]] استفاده شود، کامپایلر می‌تواند درک کند توابعی که مقدار بازگشتی دارند نمی‌توانند مقدار بازگشت داده شده‌ی آن‌ها را دور انداخت و یا از آن‌ها در زمان صدا زدن صرف نظر کرد. بنابراین با تعریف این صفت در توابع از نوع بازگشتی می‌توان پیغامی به صورت زیر را ساطع کند. مثال: #include <iostream> [[nodiscard]] int myFunction() { return 17; } int main() { myFunction(); return 0; } در مثال فوق تابع myFunction در زمان فراخوانی که مقدار بازگشتی آن بی نتیجه مانده است از سمت کامپایلر هشدار مورد نظر را دریافت خواهد کرد. این پیغام در صورتی که مقدار بازگشتی تابع به متغیری از هم نوعِ خودش ارسال شود، ساطع نخواهد شد. #include <iostream> [[nodiscard]] int myFunction() { return 17; } int main() { int func; func = myFunction(); return 0; } بخش دوم این مقاله در پست‌های بعدی ارائه می‌شود.
  8. سلام، منظور از دیوانگی این هست که اکثراً در دنیای وِب با وجود زبان‌هایی مثل php و غیره اینطور در نظر داشته باشند که خب مگه می‌شه با سی++ چنین برنامه‌هایی رو هم طراحی کرد؟ خب این برمی‌گرده به اطلاعات کمی که داریم! برای مثال ما از ابتدای شروع یادگیری سی++ اینطور فکر می‌کنیم که سی++ فقط یک زبان دانشگاهی برای پاس کردن چهارتا نمره‌ی درسی هست! برای اینکه حقایق پنهان این زبان رو بشناسیم این پست رو قبلاً آماده کردم. برای مثال کافیه یک تحقیق صورت بگیره که سایت‌های بزرگی مثل فیسبوک، آمازون، گوگل و غیره اساسشون با سی++ هست. این کار منطقی و دلایل خودش رو داره ( جاوا اسکریپت همیشه به عنوان یک ابزار خوب در سمت فرانت‌اند مطرح هست. منظور از سی++ این نیست که فرانتش رو هم با سی++ بنویسیم! طبیعتاً شما وقتی با Php یا موارد دیگر وب‌سایتی رو طراحی می‌کنید بخش فرانت و بک‌اندش رو جدا از هم ترکیب خواهید کرد. در این روش هم سمت رابط‌کاربری با HTML5, CSS3, JavaScript, Angular.JS و غیره امکان پذیر است. تمامی کد‌های منطقی سمت سی++ نوشته میشه که طبیعتاً نسبت به دیگر زبان‌ها مزایا و کیفیت خودش رو داره. بستگی داره منظورتون از سیستم کامل چی باشه! برای مثال یک وب‌سرور رو کامل می‌شه پیاده سازی کرد! اما طبیعتاً یک وب‌سایتی که شامل یک ظاهر از طراحی قالب شیک و یا گزینه‌های سمت کاربری هست (این دیوانگیه که با سی++ پیادش کنی) چون JS و HTML برای این کار ساخته شده! بنابراین شما می‌تونی با سی++ بک‌اند وب رو توسعه بدی و بقیه موارد رو با فناوری‌های مرتبط با خودش. نود‌جی‌اِس ذاتاً در جاهایی که کم میاره با سی++ قابل توسعه هست. اما خب وقتی شما می‌تونی با سی++ مستقیم وارد بحث توسعه‌ی وب بشی دیگه نگرانی کارایی نخواهی دات. البته اشاره کنم ماهیت سرعت در برنامه‌های تحت وب ذاتاً فقط بحث زبان نیست! برای مثال بحث‌های چند‌نخی، پردازش‌های موازی و غیره همه مهم هستند. حتی ممکنه شما با سی++ بهترین کد و سریع‌ترین نوعِش رو بنویسی اما با وجود یک کد خیلی ساده اما بد در سمت JS یا HTML از کارایی برنامه به شدت بکاهی! این مقاله صرفاً یک مقاله‌ی آزمایشی بود، در مورد فریم‌ورک‌های قدرتمند سی++ به زودی به معرفی انواع آن‌ها و روش‌های توسعه‌ی وب اشاره خواهد شد که طبیعتاً می‌توان به این نتیجه رسید که نه تنها دیوانگی نیست، بلکه ما با یک روند توسعه و فناوری‌های جدیدی مواجه هستیم.
  9. سلام صرفا از این جهت این سوال را میپرسم که خب تا اینجای مطلبی که نوشتین برای بسیاری از افراد، همان طور خودتون گفتین دیوانگی بنظر میرسه پس چرا یکم این دیوانگی بیشتر نباشه؟. این امکان رو هم بررسی کردین که آیا میشه جاوااسکریپت سمت فرانت رو هم با سی++ بزنیم زمین؟ یعنی یک سیستم کاملا سی++ رو بشه برای برنامه نویسی تحت وب پیاده کرد؟ حتما ازاین که مثلا نودجی.اس هم بسیار سرعت خوبی داره و سروصدای خوبی هم به پا کرده که جاوااسکریپت در دوسمت برنامه نویسی وب وارد شده و سریعت بخشیده و.... هم زیاد شنیدین، ولی خب در بحث سرعت هنوز سی و سی++ رو نمیتونن رد کنن. مشتاق خوندن پستهای بعدی تون هستم.
  10. فرهاد شیری

    سلام خوش آمدید برای برنامه نویسی اندروید، بهترین روش یادگیری آموزش زبان پایه سیستم عامل اندروید که همان جاوا می باشد را باید یاد بگیرید. بنابراین برای شروع حتما یک دوره ویدئویی مقدماتی از Java SE و بعد یک دوره مقدماتی اندروید برای شروع خیلی خوب است. برای تهیه آموزش های با کیفیت و معتبر بهتر هست که از سیستم آموزشی فانوکس استفاده کنید. سیستم آموزشی فانوکس، موفق باشید
  11. سلام خدمت کاربران محترم فروم. من تصمیم دارم وارد حوزه برنامه نویسی اندروید بشم. تجربه کد زنی دارم (html و وردپرس مقداری کار کردم). برای اندروید از کجا شروع کنم؟ چه زبانی؟ ممنون
  12. کامبیز اسدزاده

    خواهش می‌شود.
  13. سید محمد عباسی

    ممنونیم، مهندس‌جان.
  14. پچ کردن dll چه ربطی به preloader library linker می تونه داشته باشه؟ این مطلبی که دربالا بحث شده هیچ ربطی به تزریق استاتیک کد اسمبلی نداره! و یک سوال دیگه ؟ منظورتون از push کردن تمام رجیسترها چی؟ چطوری میخواهید رجیسترها را push کنید وبعدهم همه را pop کنید! بنظرم همانطور که کل این مقاله را اشتباه متوجه شدید ظاهرا در برنامه نویسی اسمبلی و روش های پچ کردن و تزریق کد هم دچار اشکال هستید. به نظرم دوست گرامی بهتره که هر مطلبی که مطالعه میکنیم را بیان نکنیم، مگه با دلیل و منطقی که بتونیم براش مثالی هم بزنیم. اصلا فلسفه هوک کردن api های ویندوز چیزه دیگه ای هست که همانطور که قبلا گفتم هیچ ربطی به این مقاله نداره!
  15. @کامبیز اسدزاده بله این یه روش به حساب میاد که در ویندوز هم قابل استفادس. به شکل های مختلف هم قابل استفادس. یکی پچ کردن مستقیم dll اصلی هست، به صورتی که به مکان کود کیو پرش بزنید اونجا تمام رجیستر هارو پوش بکنید سپس کارتونو که انجام دادید تمام رجیستر ها پاپ شن و به جای اصلی برگردین.(البته باید مکانیزم aslr غیر فعال بشه وگرنه احتمال زیاد تو اجراهای بعدی برنامه دچار مشکل میشه) راه دیگه هوک کردن با dll هست. راه دیگه پابلیک هوک کردن api هست که به ندرت(توست ویروس های قدرتمند) استفاده میشه و رفتار api رو برای همه پردازه ها تغییر میده (نمونه بسیار معروفش هم کرم استاکسنت هست). که روش سخت و غیر استانداردیم هست. البته خودم همشو تست نکردم!
  16. سید محمد عباسی

    آموزش زبان برنامه‌نویسی سوئیفت - جلسه چهارم مواردی که در این جلسه یاد خواهید گرفت: کامنت‌ها، دو ویژگی نوع‌های داده Int، آپِریِتر‌ها ( Operators )، کلمات کلیدی break,continue,fallthrough عرض ادب و احترام دارم خدمت شما عزیزان. در این جلسه به مواردی که در بالا گفته شده، پرداخته میشه، پس تا انتها با من همراه باشید و امیدوارم از این جلسه هم نهایت استفاده رو بکنید. کامنت‌ها در زبان برنامه‌نویسی سوئیفت مثل اکثر زبان‌های برنامه‌نویسی دیگه، از کامنت‌ها استفادهای زیادی میشه و معمولا برای هدفی کامنت‌ها نوشته میشن و می‌تونن شامل موارد زیر باشن: برای غیر‌فعال کردن موقتی یک قسمت/بخش از کُد برای توضیح دادن یک قسمت/بخش از کُد برای دیگر برنامه‌نویسان/توسعه‌دهندگان یا توضیح کُد برای اینکه در مراجعات بعدی به کُدهای پروژه کارکرد هر قسمت از برنامه را متوجه شوید انواع کامنت‌ها در زبان برنامه‌‌نویسی سوئیفت: تَک خطی (‌ single-line ) چند خطی ( multi-line ) در کامنت تَک خطی، با گذاشتن دو علامت // می‌توانید توضیحات خود را فقط در همان خط درمورد کُد مورد نظر بنویسید و بعد از آن کامنت شما در واقع در حال تعریف دستور جدید هستید! به این مثال دقت کنید: let _web_site_name : String = "www.iostream.ir" print(_web_site_name) // Ouput the string of www.iostream.ir در مثال بالا همان‌طور که مشاهده می‌کنید از کامنت تَک خطی استفاده کردیم، و بعد از این کامنت شما نمی‌توانید انتظار داشته باشید که در خط جدید دوباره حالت کامنت‌گذاری برای شما همچنان فعال باشد! چرا که در بعدی دستوری جدید داریم نه کامنتی ادامه‌ی کامنت قبل!. و اما کامنت چند خطی که اسمش هم روشه، تا هر چند‌تا خط تا موقعی که آخر کامنت رو نَبسته باشید، می‌تونید توضیحات بنویسید. به مثال زیر دقت کنید: let _web_site_name : String = "www.iostream.ir" /* We can also use from of print("String.. and \(_web_site_name)") */ print(_web_site_name) در مثال بالا که مشاهده می‌کنید، شما هیچ محدودیتی برای اضافه کردن توضیحات بیشتر برای کُد‌های خود ندارید و تا هر چند خط توضیحات می‌توانید استفاده کنید. دو ویژگی نوع داده‌ی Int اگر بخواهیم کوچک‌ترین و بزرگ‌ترین عدد موجود از نوع داده‌ی Int را بدست آوریم، از دو ویژگی max,min استفاده می‌کنیم. هر دو ویژگی به همراه مثال در زیر آورده شده‌اند: print("Max => \(Int.max)") print("Min => \(Int.min)") با اجرای کد‌های بالا،‌ بزرگترین مقدار موجود نوع داده‌ی Int و همچنین کوچک‌ترین آن به شما نمایش داده می‌شود. آپِریِتر‌ها (‌ Operators ) آپِریِتر‌ها در هر زبان برنامه‌نویسی به عنوان پایه و اساس محاسبات و در بعضی موارد برای کارهای دیگر استفاده می‌شود. محاسباتی مانند، جمع، تفریق،تقسیم،ضرب و باقی مانده. در سوئیفت این 8 دسته آپرِیِتر وجود دارد: آپِریِتر‌ اِنتسابی ( Assigment Operator ) آپرِیِتر‌های محاسباتی ( Arithmetic Oprerator ) آپِریِتر‌ باقی‌مانده ( Remainder Operator ) آپِریِتر‌های مُرکب ( Compound Assigment Operator ) آپِریِتر‌های مقایسه‌ای ( Comparison Operators ) آپِریِتر ترِنِری ( Ternary Conditonal Operators ) آپِریِتر دامِنه ( Range Operator ) آپِریِتر‌های منطقی ( Logical Operators ) این‌ها، کل آپِریِتر‌ها در سوئیفت هستند که هر کدام عمل مخصوص به خود را انجام می‌دهند. در مثال‌های زیر هر کدام از این آپِریِتر‌ها را به همراه مثال برای شما آورده‌ایم. آپِریِتر‌های اِنتسابی ( Assigment Operator ) در کل اینکه ما یک مقداری را به متغییری انتساب می‌دهیم، عملا داریم از آپِریِتر‌‌ انتساب ( = ) استفاده می‌کنیم. چرا که کُدنویسی از سمت چپ شروع می‌شود و کاملا منطقی هم هست که مقدار دهی به یک متغییر از سمت چپ صورت می‌گیرد که مقدار سمت راست قرار می‌گیرد، با استفاده از آپِریِتر انتساب (‌ = ) در مابین مقدار و نام و نوع متغییر قرار می‌گیرد و عمل انتساب مقدار به متغییر را انجام می‌دهد. به مثال زیر دقت کنید: let _web_site_name : String = "www.iostream.ir" // Assigment Operator ( = ) print("Type of \(type(of : _web_site_name ) and the website of name \(_web_site_name)") در مثال بالا مشاهده می‌کنید که با استفاده از آپِریَتر انتساب (‌ = )‌، مقدار www.iostream.ir که یک مقدار رشته‌ای/متنی است را در متغیر web_site_name ذخیره می‌کنیم. در خط بعد هم نوع متغییر و مقدار موجود در متغییر web_site_name ذخیره نمایش می‌دهیم. آپرِیِتر‌های محاسباتی ( Arithmetic Oprerator ) در قسمت‌هایی از پروژه شده که ما باید محاسباتی رو انجام بدیم. این کار با استفاده از آپِریِتر‌های محاسباتی ( Arithmetic Operator ) صورت می‌گیرند. این آپِریِتر‌ها شامل: +،-،/،* و ٪ است. برای هر کدام از این آپریِترها، مثال‌هایی در زیر آورده شده است: آپِریِتر + var number_one, number_two : Int8 number_one = 50 number_two = 50 print("Result = > ", number_one + number_two) // Output the number 100 در مثال بالا همان طور که مشاهده می‌کنید، ابتدا دوم متغییر با نوع Int8 تعریف کرده و سپس در خطوط بعد به آن‌ها مقادیر ۵۰ را داده‌ایم. در نهایت عمل جمع ( + ) را روی آن‌ها به صورت مستقیم انجام و نمایش می‌دهیم. یا ساده‌تر بخواهیم تعریف کنیم، آپِریِتر ( + ) عمل جمع کردن اعداد و یا متصل کردن دو رشته را بر عهده دارد: var web_site_name, platform_name : String web_site_name = " www.iostream.ir :)" platform_name = " www.fanoox.com ;)" print("Binding two string => ", web_site_name + platform_name) // Ouput the website name and platform name => www.iostream.ir :) www.fanoox.com ;) و به همین راحتی می‌توانید تا بی‌نهایت عمل جمع و متصل کردن رشته‌ها را انجام دهید. تنها نکته‌ای که باید توجه داشته باشید این است که سوئیفت در برخورد با اعداد و این آپِریَتر، آن عبارت را محاسباتی در نظر می‌گیرد و در برخورد دو تا چند رشته، آن عبارت را عمل متصل کردن و الحالق ( concatentation ) در نظر می‌گیرد. آپِریِتر - این آپِریِتر برای کم کردن دو مقدار عددی از هم استفاده می‌شود، همان‌طور که در مثال زیر مشاهده می‌کنید: var number_one, number_two : Int8 number_one = 80 number_two = 30 print("Result => ", number_one - number_two) // Output the number 50 مثال بالا به خوبی نشان می‌دهد که دو مقدار ۸۰ و ۳۰ از هم کم شده با استفاده از آپِریِتر ( - ) و در نتیجه، خروجی برابر ۵۰ خواهد بود. آپِریِتر * این آپِریِتر عمل ضرب کردن دو عدد را انجام می‌دهد، به مثال زیر دقت کنید: var number_one, number_two : Int8 number_one = 50 number_two = 20 print("Result => ", number_one * number_two) // Output the number 1000 آپِریِتر ( *‌ ) عمل ضَرب را انجام می‌دهد و نباید به حرف ( x ) که شبیه به ضرب در ریاضیات است اشتباه گرفته شود. آپِریِتر / این آپِریِتر عمل تقسیم کردن دو عدد را انجام می‌دهد. به مثال زیر دقت کنید: var number_one, number_two : Double number_one = 50.0 number_two = 20.0 print("Result => ", number_one / number_two) // Output the number 2.5 در محاسباتی که عمل تقسیم را انجام می‌دهیم باید به این نکته دقت کنیم که اگر پروژه‌ی ما عملا برای محاسبات کار خاصی است باید از نوع داده‌ی Double یا Float استفاده کنیم که البته در محاسبات معمولی، نوع داده‌ی Float جواب‌گوی نیاز ما هم هست، اما در محاسباتی که نیاز به دقت بالایی دارند باید از نوع داده‌ی Double استفاده کنیم. آپِریِتر ٪ این آپِریِتر را با علامت درصد که شبیه همین است اشتباه نگیرید! چرا که در دنیای واقعی ما، علامت درصد برای نشان دادن مقداری از چیزی در یک محصول یا خدمات است ولی در دنیای کامپیوتر و برنامه‌نویسی این علامت که آپِریِتر خوانده می‌شود، به معنای باقی مانده‌ی بین دو عدد است که بعد از تقسیم‌های پی‌درپی که صورت می‌گیرد، بدست می‌آید. این باقی مانده یا ۰ است یا ۱. حتما شما هم عاشق صفر و یکی هستید که اساس کار کامپیوتر و سیستم شما را تشکیل می‌دهد!. یک مثال در زیر ببینید تا متوجه کارکرد این آپِریِتر شوید: var number_one, number_two : Int8 number_one = 10 number_two = 2 print("Result => ", number_one % number_two) // Output the number 0 اگر جزئی بخواهیم وارد شویم به این صورت است که ابتدا عدد ۱۰ بر ۲ تقسیم ( آپِریِتر / ) شده و سپس حاصلی که بدست می‌آید ۵ است و سپس همین ۵ دوباره تقسیم بر ۲ شده و ۲ بدست می‌آید و در اینجا ۲ ٪ ۲ می‌شود ۰. آپِریِتر باقی‌مانده ( Reminder Operator ) این آپِریِتر همان‌طور که در بالا و در قسمت آپِریِتر‌های محاسباتی قرار گرفته بود، کار محاسبه‌ی باقی‌مانده‌ی دو عدد را انجام می‌دهد: var number_one, number_two : Int8 number_one = 10 number_two = 2 print("Result => ", number_one % number_two) // Output the number 0 آپِریِتر‌های مُرکب ( Compound Assigment Operator ) که شامل عبارت‌های کوتاه‌شده یا به اصطلاح میانبُری برای عمل انتساب و محاسبه را فراهم می‌کند که شامل: =+،=-،=*،=/،=٪ است. در زیر توضیح مختصر به همراه یک مثال آورده شده است. آپِریِتر =+ در این حالت ما هم عمل انتساب را داریم و هم عمل جمع، با یک تیر دو نشان! به مثال زیر دقت کنید. var number_one : Int8 = 50 number_one += 50 print("Result =>", number_one) // Output the number 100 در خط دوم که ما با آن کار داریم، متغییر number_one به علاوه‌ی مقدار قبلی خودش، مقدار ۵۰ را هم به آن اضافه کرده و در نهایت در خود متغییر number_one ذخیره و نتیجه ۱۰۰ نمایش داده می‌شود. که بدون استفاده از میانبُر، به این شکل بود: var number_one : Int8 = 50 number_one = number_one + 50 print("Result =>", number_one) // Output the number 100 حتی می‌توانیم برای اتصال یک رشته به رشته‌ی دیگر استفاده کنیم: var web_site_name : String = "www.iostream.ir :) " web_site_name += " www.fanoox.com ;) " print("Result =>" web_site_name) // Ouput the web site of name => www.iostream.ir :) www.fanoox.com ;) که بدون استفاده از میانبُر به این شکل نوشته می‌شُد: var _web_site_name_and_platform_name : String = "www.iostream.ir :) " + " www.fanoox.com ;) " print("Result => ", _web_site_name_and_platform_name) // Ouput the web site of name and platform name => www.iostream.ir :) www.fanoox.com ;) آپِریِتر =- عمل تفریف و انتساب آن به مقدار فعلی متغییر را انجام می‌دهد. به مثال زیر دقت کنید:‌ var number : Int8 = 80 number -= 30 print("Result =>", number) // Ouput the number 50 مقدار ۸۰ که مقدار فعلی متغییر number است، از مقدار ۳۰ که در سمت راست متغییر قرار دارد، کم می‌شود و در نهایت مقدار ۵۰ در همان متغییر یعنی ‌number ذخیره می‌شود. آپِریِتر =* عمل ضرب و انتساب مقدار سمت راستی در مقدار فعلی متغییر سمت چپ را انجام می‌دهد. به مثال زیر دقت کنید: var number : Int8 = 80 number *= 30 print("Result =>", number) // Ouput the number 2400 آپِریِتر =/ مشابه آپِریِتر تقسیم ( / )‌، عمل تقسیم و انتساب آن به متغییر سمت چپ انجام می‌دهد. به مثال زیر دقت کنید: var number : Int8 = 10 number /= 2 print("Result =>", number) // Ouput the number 5 آپِریِتر =٪ عمل باقی‌مانده‌ی دو عدد که شامل مقدار فعلی متغییر سمت چپ و مقدار سمت را است را محاسبه کرده و در متغییر سمت چپ ذخیره می‌کند. به مثال زیر دقت کنید: var number : Int8 = 10 number ٪= 5 print("Result =>", number) // Ouput the number 0 آپِریِتر‌های مقایسه‌ای ( Comparison Operators ) برای مقایسه‌ی بین دو مقدار و در نتیجه برگرداندن مقدار True یا False مورد استفاده قرار می‌گیرند. بیشترین استفاده‌ی آنها در شرط‌هاست، اما می‌توان به صورت مستقیم هم از آن‌‌ها هم استفاده کرد. این آپِریِتر‌ها شامل ==،=!،>،<،=<،=>،==!،=== است. برای هر کدام مثالی در زیر آورده شده است. آپِریِتر == برای مقایسه دو مقدار استفاده می‌کنیم که مقدار در صورتی که مقادیر دو طرف مساوی باشند، مقدار True و در غیر اینصورت مقدار False برگشت داده می‌شود. به مثال زیر دقت کنید: print("True and False => ", 2 == 2) // Output the true print("True and False => ", 2 == 3) // Output the false در مثال بالا چونکه ۲ با ۲ برابر است،‌ مقدار نمایش داده شده،‌ true است. و در خط بعدی چونکه مقدار ۲ برابر با ۳ نیست،‌ مقدار false نمایش داده می‌شود.همچنین می‌توانید در شرط‌ها و حلقه‌ها هم استفاده کنید: if 2 == 2 { print("Ok!") }else { print("NO!") } // Ouput the string Ok! آپِریِتر =! اگر مقدار برابر با مقدار مقابل خودش نبود، نتیجه true و در غیر اینصورت نتیجه false خواهد بود. علامت ! ( نَقیض )‌ دقیقا معنا و مفهوم ( == ) را عوض می‌کند. به مثال زیر دقت کنید: print("True and False => ", 2 != 3) // Output the true print("True and False => ", 2 != 2) // Output the false در مثال بالا، ۲ مساوی ۳ نیست و این درست است. در خط بعدی ۲ مساوی با ۲ نیست که این درست نیست و مساوی هستش،‌ پس نتیجه false است. آپِریِتر > اگر مقدار سمت چپ کوچکتر از مقدار سمت راست بود، نتیجه true و در غیر اینصورت نتیجه false است. به مثال زیر دقت کنید:‌ print("The operator ( < ) => ", 1 < 2) // Output the boolean true print("The operator ( < ) => ", 2 < 1) // Output the boolean false آپِریِتر <‌ اگر مقدار سمت چپ بزرگتر از مقدار سمت راست بود، نتیجه true و در غیر اینصورت نتیجه false است. به مثال زیر دقت کنید: print("The operator ( > ) => ", 1 > 2) // Output the boolean false print("The operator ( > ) => ", 2 > 1) // Output the boolean true آپِریِتر =< اگر مقدار سمت چپ، بزرگتر یا مساوی مقدار سمت راست بود، نتیجه true است، در غیر اینصورت، نتیجه false خواهد بود. به مثال زیر دقت کنید: print("The operator ( >= ) => ", 1 >= 1) // Output the boolean true print("The operator ( >= ) => ", 1 >= 2) // Output the boolean false آپِریِتر => اگر مقدار سمت چپ، کوچکتر یا مساوی مقدار سمت راست بود، نتیجه true است، در غیر اینصورت، نتیجه false خواهد بود. به مثال زیر دقت کنید: print("The operator ( <= ) => ", 1 <= 2) // Output the boolean false print("The operator ( <= ) => ", 1 <= 1) // Output the boolean true نکته:‌ اولویت آپِریِتر مساوی (‌ = ) در این مورد بالا‌تر از آپِریِتر < یا > است و بنابر این در حلقه‌ها اگر این این آپِریِتر باشد، مبنا بر همین آپِریِتر قرار می‌گیرد. آپِریِتر === این آپِریِتر برای مقایسه‌ی دو شئ ( object ) استفاده می‌شود. اگر هر دو شئ از یک مرجع ( refrence ) بودند یا به عبارت دیگر شئ‌های ساخته شده در حافظه‌ی به نام Heap با تمام ویژگی‌ها و متغییر‌‌ها نگه‌داری می‌شوند و اگر شئ دیگر از همان حافظه‌ای که یک شئ دیگر استفاده می‌کند باشد، این آپِریِتر درمورد آن دو شئ نتیجه‌ی true و در غیر اینصورت نتیجه‌ی false را نمایش می‌دهد. در مبحث شئ‌گرایی بیشتر در این مورد صحبت ‌می‌کنیم،‌ در حال حاضر فقط همین را بدانید، کافیست. به مثال زیر دقت کنید: class WebsitePlatform { var web_site_name, platform_name : String init(web_name : String, platform : String) { self.web_site_name = web_name self.platform_name = platform } } let _web_site_and_plat_form_one = WebSitePlatform(web_name : "www.iostream.ir", platform : "www.fanoox.com") let _web_site_and_plat_form_two = WebSitePlatform(web_name : "www.iostream.ir", platform : "www.fanoox.com") if _web_site_and_plat_form_one === _web_site_and_plat_form_two { print("This is refrence!") }else { print("No,this is not refrence!") } اگر این کُد را خروجی بگیرید، به شما پیغام NO, this is not refrence را می‌دهد. چرا که هر دو شئ به صورت جداگانه در حافظه‌ی Heap ذخیره شده‌اند و هیچ‌کدام به دیگر کاری ندارد و به اصطلاح با هم ارتباطی ندارند و هر یک کَشک خودش را می‌سابد. و اگر ما بیایم به این شکل عمل کنیم، آنوقت دیگر یک ارجاع داریم به شئ‌ای مشخص: class WebsitePlatform { var web_site_name, platform_name : String init(web_name : String, platform : String) { self.web_site_name = web_name self.platform_name = platform } } let _web_site_and_plat_form_one = WebSitePlatform(web_name : "www.iostream.ir", platform : "www.fanoox.com") let _web_site_and_plat_form_two = _web_site_and_plat_form_one if _web_site_and_plat_form_one === _web_site_and_plat_form_two { print("This is refrence!") }else { print("No,this is not refrence!") } به جای ایجاد شئ جدید، همان شئ اول را به متغییر دوم انتساب می‌دهیم که الان در واقع دو شئ داریم که شئ دومی به شئ اولی اشاره می‌کند و حالا باید این دو شئ، دوتایی کَشک بسابن! یعنی اینکه الان دوتایی به هم در ارتباطن و شئ دومی ارجاعیست به شئ اول. نتیجه خروجی هم This is refrence است. آپِریِتر ==! اگر دو شئ از یک مرجع نبودند، و هر کدام در حافظه‌ای جداگانه نگه‌داری می‌شدند، نتیجه به صورت true و اگر دو شئ‌ از یک مرجع بودند، نتیجه false خواهد بود. کاملا برعکس آپِریِتر (‌ ===‌ ). به مثال زیر دقت کنید: class WebsitePlatform { var web_site_name, platform_name : String init(web_name : String, platform : String) { self.web_site_name = web_name self.platform_name = platform } } let _web_site_and_plat_form_one = WebSitePlatform(web_name : "www.iostream.ir", platform : "www.fanoox.com") let _web_site_and_plat_form_two = WebSitePlatform(web_name : "www.iostream.ir", platform : "www.fanoox.com") if _web_site_and_plat_form_one !== _web_site_and_plat_form_two { print("This is refrence!") }else { print("No,this is not refrence!") } مثال بالا هم که کاملا واضح است! اینکه اگر دو شئ با هم ارجاعی نداشتند، پس نتیجه طبق این آپِریِتر true است و در غیر اینصورت اگر ارجاع داشتند، نتجیه false و شرط آخر اجرا خواهد شد که No, this is not refrence است. آپِریِتر ترِنِری ( Ternary Conditonal Operators ) سه تا قسمت داره: مسئله/شرط مقدار اول مقدار دوم شرط در ابتدا قرار می‌گیره و سپس به دنبال آن آپِریِتر ? و بعد از آن جواب اول در صورت درست بودن شرط که برگشت داده می‌شود و علامت کالُن ( : ) در صورتی که نتیجه نادرست یا false باشد در شرط، مقدار بعد از کالُن/دونقطه ( : ) برگشت داده می‌شود. به مثال زیر دقت کنید: let _web_site_name_and_platform_name : String = 2 > 1? "www.iostream.ir" : "www.fanoox.com" print("Result =>", _web_site_name_and_platform_name) // Output the www.iostream.ir در مثال بالا همان‌طور که مشاهده می‌کنید، ابتدا شرط/مسئله قرار می‌گیرد و سپس مقدار بعد آپِریِتر ? و مقدار اول و دوم که با کالُن ( : ) از هم جدا می‌شوند. در این مثال نتیجه، www.iostream.ir است، چرا که ۲ بزرگتر از ۱ است و این از لحاض منقطی نتیجه‌ی true دارد. آپِریِتر دامِنه ( Range Operator ) این آپِریِتر در حلقه‌ها استفاده می‌شود و نحوه‌ی کار آن‌ را در جلسات قبل توضیح داده‌ام: for index_number_one in 0...20 { print(index_number_one, separator : " ",terminator : "") // Output the number 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 } for index_number_two in 0..<20 { print(index_number_two, separator : " ",terminator : "") // Output the number 0 1 2 3 4 5 6 7 8 9 10 11 12 13 15 16 17 18 19 } آپِریِتر‌های منطقی ( Logical Operators ) شامل آپِریِتر‌های !،&&،|| است. که بیشتر استفاده‌ی آن‌ها در حلقه‌هاست، اما شما می‌توانید در هر جایی از پروژه‌ی خودتان که نیاز به این آپِریِتر‌ها داشتید، به صورت مستقیم استفاده کنید. آپِریِتر ! ( نَقیض ) کار این آپِریِتر، برعکس کردن یا نَقیض کردن یک مقدار هستش که ممکنه true یا false باشه. به عنوان مثال اگه مقدار متغییری true بود و این آپِریِتر رو در ابتدای اون مقدار قرار دادید، خروجی برابر است با false. و همین مورد هم برعکس صدق می‌کند، یعنی اگر شما مقدار متغییری false داشتید، با گذاشتن این عبارت در ابتدای متغییر، نتیجه true می‌شود. این مثال زیر را ببینید: var is_name_web_site_iostream : Bool = false print(!is_name_web_site_iostream) // Output the bool true is_name_web_site_iostream = true print(!is_web_site_iostream) // Output the bool false آپِریِتر && اگر در شرط یا عبارتی بخواهیم دو شرط را بررسی کنیم که هر دو هم حتما باید درست ( true ) باشند از این آپِریِتر استفاده می‌کنیم. به مثال زیر دقت کنید: let web_site_name, platform_name : String web_site_name = "www.iostream.ir" platform_name = "www.fanoox.com" if web_site_name == "www.iostream.ir" && platform_name == "www.fanoox.com" { print(web_site_name, platform_name) } else { print("None") } اگر در مثال بالا، هر دو شرط مبنی بر اینکه دو مقدار متغییر تعریف شده باید برابر با مقدار تعیین شده در شرط باشند تا مقادیر چاپ شوند. در غیر اینصورت با خروجی None روبرور خواهیم شد. آپِریِتر || این یکی زیاد گیر نمیده که حالا حتما باید هر دو شرط با هم برقرار باشن! یکی از شرط‌ها در بین چندین شرط که برقرار باشه و به عبارتی نتیجه درست (‌ true ) برگردونه، وارد بدنه‌ی شرطه میشه و دستورات رو اجرا می‌کنه. اگه تمامی شرط‌ها نادرست (‌ false ) بودند، دستورات داخل بدنه اجرا نخواهند شد. به مثال زیر دقت کنید: var web_site_name, platform_name : String web_site_name = "www.iostream.ir" platform_name = "www.fanoox.com" if web_site_name == "www.iostream.ir" || platform_name == "www.fanoox.ir" { print(web_site_name, platform_name) } else { print("None") } در مثال بالا شرط دوم برقرار نیست! چرا که متغییر platform_name با مقدار سمت راست آن برابر نیست. اما از آنجایی که از آپرِیِتر ||‌ استفاده کردیم، پس شرط اول درست بوده و دستورات داخل بدنه‌ی شرط if اجرا می‌شوند. کلمات کلیدی continue,break,fallthrough کلمه‌ی کلید continue اگر بخواهیم در یک حلقه در یک جایی به بعد دستورات اجرا نشوند و مجددا حلقه اجرا شود، از این کلمه‌ی کلید کمک می‌گیرم. به مثال زیر دقت کنید: for index in 0...20 { if index == 5 { continue } print(index) } /* Output the number 0 1 2 3 4 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 */ همان‌طور که مثال بالا مشاهده‌ کردید، در حلقه‌ی for شرط داخل حلقه بر این مبنا بود که اگر متغییر index مساوی مقدار ۵ شد، ادامه‌ی دستورات را ادامه نده ( continue ) و مجدد حلقه را از سر بگیر. بخاطر همین است که عدد ۵ نمایش داده نشده. کلمه‌ی کلید break با این کلمه‌ی کلید به راحتی می‌توانید هر جایی از حلقه که دیگر نیازی نداشتید که حلقه ادامه ندهد، با این کلمه کلید حلقه را متوقف یا به اصطلاح بشکنید!. با این کار دیگر حلقه تکرار نشده و دستورات بعد از حلقه اجرا خواهند شد. به مثال زیر دقت کنید: for index in 0...5 { if index == 2 { break } print(index) } /* Output the number 0 1 */ کلمه‌ی کلید fallthrough شاید در جایی از دستوری شرطی switch لازم داشتید که caseهای بعدی هم اجرا شوند. با این کلمه‌ی کلیدی می‌توانید این کار را انجام دهید. به مثال زیر دقت کنید: let _number : Int8 = 1 switch _number { case 2: print(2) case 1: print(1) fallthrough case 3: print(3) fallthrough default: print("None") } بعد از هر caseی که می‌خواهید اجرا شود باید این کلمه‌ی کلید را قرار دهید. منتظر جلسه‌ی پنجم این دوره‌ی آموزشی باشید.
  17. سلام من میخواهم دوباره مقدار و آیکن اکشن دوم را تغییر دهم. اما جواب نمی‌دهد. چرا؟ Notification.Builder notification = new Notification.Builder ( this ) .setSmallIcon ( R.drawable.ic_play ) .setContentTitle ( "madaraneh.mp3" ) .setContentText ( "madaraneh" ) .setContentIntent ( PendingIntent.getActivity ( this, 0, new Intent ( this, MusicPlayerActivity.class ), 0 ) ) .setOngoing ( true ) .addAction ( R.drawable.ic_rewind, "Rewind", rewindPending ) .addAction ( R.drawable.ic_play, "Play", playPending ) .addAction ( R.drawable.ic_forward, "Forward", forwardPending ) ; NotificationManager notificationManager=(NotificationManager)getSystemService ( NOTIFICATION_SERVICE ); notification.build ().actions[1]=new Notification.Action (R.drawable.a1,"hhhhhhhh",playPending); notificationManager.notify ( 12,notification.build () ); کدی که برای ویرایش آیکن اکشن دوم نوشتم این است: notification.build ().actions[1]=new Notification.Action (R.drawable.a1,"hhhhhhhh",playPending);
  18. با سلام همانطور که می دانید وقتی یک متغیر کلاس اتوماتیک را به صورت استاتیک در بدنه یک تابع تعریف میکنید و درصورتی که این تابع به صورت external تعریف شده باشه، قطعا با هر بار فراخوانی این تابع مقدار متغیر استاتیک فقط یکبار در اولین فراخوانی مقدار دهی خواهد شد و در فراخوانی های بعدی آخرین مقدار خود را حفظ خواهد کرد. بنابراین نکته ای که میتونه خیلی کاربردی باشه این هست که رفتار کامپایلر با متغیرهای استاتیک درون یک تابع template براساس آرگومان template تابع متفاوت خواهد بود، یعنی کامپایلر نوع استاتیک را براساس نوع آرگومان تابع template تعیین میکند و در section .rodata چندین نگارش از متغیر استاتیک را می نویسد، پس نتیج میگیرم که متغیرهای استاتیکی که در بدنه یک تابع template تعریف شده اند برای تابع یکتا نیستند و مقادیر مختلفی برای تابع ساخته شده است. به همین علت در زمان استفاده از یک تابع template و متغیرهای استاتیک حتما به نوع آرگومان ارسالی به تابع دقت داشته باشید که نوع استاتیک تعریف شده در بدنه تابع میتواند مقادیر مختلفی را به شما نشان دهد و به همین سادگی گرفتار یکی از باگهای منطقی در زمان اجرا شوید. با توضیحاتی که ارائه شد به مثال زیر توجه کنید... template <typename T> void ef1() { static int stat = 0; std::cout << stat++; }; و اگر من دستورات زیر را فراخوانی کنم... ef1<int>(); ef1<int>(); ef1<int>(); با اجرای کد بالا قطعا مقادیر خروجی 012 را خواهم داشت. ولی اگر از دستورات زیر استفاده کنم... ef1<int*>(); ef1<int*>(); شاید انتظار داشتید که خروجی برنامه بعد از اجرای دستورات بالا مقدار 34 را نمایش میداد ولی خیر خروجی برنامه 01 خواهد بود. ویا اگر... ef1<int&>(); ef1<int&>(); بازهم خروجی 01 خواهد بود. ویا حتی اگر... ef1<const int>(); ef1<const int>(); وبازهم خروجی 01 خواهد بود. پس حتما در زمان طراحی شی گرائی و چند ریختی در زمان اجرا در هنگام تعریف کلاسها ویا توابعی که به صورت الگو هستند، اگر از نوع استاتیک استفاده میکنید دقت لازم را داشته باشید. البته یک نکته ای که زبانی سی++ را از سایر زبانها متمایز میکند، همین تکنیک هست که به لطف وجود همچنین تکنیکی شما امکان طراحی یک کلاس template که به صورت singletone باشد را خواهید داشت، یعنی کلاسی که برای انواع آبجکتهای شما یک رفرنس یکتا ایجاد کند تا مجبور نباشید که برای هر آبجکتی که قصد استفاده از الگوی singletone را برایش داشتید جداگانه یک کلاس بنویسید. به همین علت هست که زبانهای مثل جاوا ویا سی شارپ امکان ایجاد یک کلاس ژنریک سینگلتون را ندارند.! (البته در زبان سی شارپ می توان کلاس ژنریک سینگلتون تعرف کرد ولی به علت قوانین مدیریت حافظه ای که در سی شارپ وجود دارد، نمی توان تضمین کرد که یک کلاس ژنریک سینگلتون واقعا به یک کپی اشاره داشته باشد.)
  19. سلام خسته نباشید من می‌خواهم اپلیکیشنی بنویسم که وقتی شارژ گوشی به 90 درصد رسید شارژ شدن تمام شود. با این که گوشی به برق وصل است. می‌شود در این رابطه کمکم کنید؟ ممنون
  20. به نام خدا در این مطلب قصد داریم تا طریقه پیکربندی پایگاه داده MySQL را با استفاده از کامپایلر مایکروسافت بر روی سیستم عامل ویندوز، بررسی نماییم. در ابتدا می‌بایست پایگاه داده MySQL را بر روی سیستم خود نصب نماییم. بدین منظور به آدرس این آدرس رفته و سپس و نصاب آنلاین یا آفلاین آن را دریافت و بر روی سیستم خود نصب می‌نماییم. حال لازم است تا مسیر qmake مربوط به کیت مورد نظر واقع در محل نصب کتابخانه کیوت به متغیر محیطی Path سیستم عامل معرفی شود. در اینجا قصد داریم تا از MSVC 2017 64 bit استفاده کنیم که بر روی سیستم عامل 64 بیتی اجرا شده و خروجی دودویی برای سیستم عامل 64 بیتی تولید می‌کند. مطابق شکل زیر مسیر qmake مورد نظر را به Path سیستم عامل اضافه می‌کنیم: پس از این کار از منوی Start پوشه Visual Studio 2017 را انتخاب کرده و سپس x64 Native Tools Command Prompt for VS 2017 را انتخاب کرده تا کنسول باز شود. حال می‌بایست به آدرس محل درایور پایگاه داده کیوت برویم. بدین منظور دستور زیر را در کنسول وارد می‌کنیم: C:\Program Files (x86)\Microsoft Visual Studio\2017\BuildTools>F: F:\>cd F:\Softwares\Qt\5.13.1\Src\qtbase\src\plugins\sqldrivers دستور اول به منظور تغییر درایو از C به F وارد شده و دستور دوم آدرس محل نصب کیوت روی سیستم نگارنده مطلب می‌باشد. حال دستور زیر را وارد می‌کنیم: qmake -- MYSQL_INCDIR="C:\Program Files\MySQL\MySQL Server 8.0\include" MYSQL_LIBDIR="C:\Program Files\MySQL\MySQL Server 8.0\lib" فراخوانی دستور qmake سبب ایجاد یک makefile شده که بعدا برای کامپایل درایور MySQL استفاده می‌شود. آدرس‌های بالا نیز محل نصب پایگاه داده MySQL در حالت پیشفرض را نشان میدهد. پس از اتمام عملیات نتیجه زیر می‌بایست حاصل شود: ملاحظه می‌شود که در مقابل MySql کلمه yes نوشته شده که این به معنی موفقیت آمیز بودن یافتن درایور MySQL می‌باشد. در نهایت با دستور زیر عملیات کامپایل آغاز می‌شود: nmake sub-mysql پس از اتمام این مرحله نیز در پایان دستور زیر را اجرا کرده تا فایل‌های کامپایل شده، نصب شوند: nmake install محل نصب این فایل‌های راه انداز درایور در مسیر زیر می‌باشد: F:\Softwares\Qt\5.13.1\Src\qtbase\src\plugins\sqldrivers\plugins\sqldrivers در مسیر بالا دو فایل به نام‌های qsqlmysql.dll و qsqlmysqld.dll وجود دارد که باید در کنار فایل اجرایی برنامه کامپایل شده قرار گیرد تا برنامه به درستی اجرا شود. همچنین در مسیر: C:\Program Files\MySQL\MySQL Server 8.0\lib فایل libmysql.dll وجود دارد که می‌بایست در مسیر فایل اجرایی برنامه قرار گیرد. در پایان نوبت به این رسیده تا با ایجاد یک پروژه آزمایشی در Qt Creator بررسی کنیم تا همه چیز به درستی پیکربندی شده باشد. قبل از آن می‌‎بایست یک پایگاه داده آزمایشی در MySQL ایجاد کرده و سپس با استفاده از کتابخانه کیوت به آن متصل شویم. ابتدا خط فرمان MySQL را باز کرده و دستور زیر را وارد می‌کنیم: CREATE DATABASE mydatabase; که mydatabase نام پایگاه داده ایجاد شده می‌باشد. حال پس از ایجاد یک پروژه ساده در Qt Creator محتویات فایل .pro را مطابق شکل زیر وارد می‌کنیم: QT += core sql TEMPLATE = app CONFIG += console c++11 CONFIG -= app_bundle SOURCES += \ main.cpp و در فایل main.cpp خواهیم داشت: #include <iostream> #include <QtSql/QSqlDatabase> #include <QtSql/QSqlError> #include <QDebug> using namespace std; int main() { QSqlDatabase db {QSqlDatabase::addDatabase ("QMYSQL")}; db.setHostName ("localhost"); db.setDatabaseName("mydatabase"); db.setUserName ("root"); db.setPassword ("Inception 2010"); if(db.open ()) { qDebug() << "Success!"; } else { qDebug() << db.lastError ().text (); } } با ساخت و اجرا پروژه باید پیام Success! در خروجی نمایش داده شود. این یعنی پایگاه داده MySQL با موفقیت نصب و پیکربندی شده است.
  21. سید محمد عباسی

    آموزش زبان برنامه‌نویسی سوئیفت - جلسه سوم مواردی که در این جلسه یاد خواهید گرفت: انواع داده و حلقه‌ها جلسه‌ی سوم رو اختصاص میدیم به بحث انواع داده و حلقه‌ها. در زبان برنامه‌‌نویسی سوئیفت ما با انواعی از داده روبرو هستیم! که البته طبق دیگر زبان‌های برنامه‌نویسی انواع نوع داده پرکابرد رو معرفی می‌کنیم و همچنین دیگر نوع‌های داده رو در ادامه بازگو می‌کنیم که شما با دقت بتونید در پروژه‌های خودتون نوع‌های داده‌ی خودتون رو انتخاب کنید. همچنین باید در نظر داشته باشید که در هر پروژه‌ی نرم‌افزاری به کار بردن نوع‌های داده‌‌ای که اصلا شاید ضروری نباشه و با یه نوع داده‌ی دیگه که حافظه‌ای به مراتب کمتر از نوع داده‌ی قبلی که تعریف کردید بگیره، کارتون راه بیفته. در هر صورت در انتخاب نوع‌های داده در پروژه‌های خودتون نهایت دقت رو به خرج بدید! کِی دوست نداره که پروژه‌ای کارآمد و بهینه داشته باشه که هر توسعه‌ دهنده‌ای با دیدن نظم و بهینه بودن پروژه‌اش چَه‌چَه و بَه‌بَه بزنه؟!. درمورد حلقه‌ها هم یک توضیح مختصر بدم و بریم سراغ کُد‌نویسی. همه‌ی ما در برنامه‌نویسی نیاز داریم که چندین خط کد رو بنویسم تا در نهایت برنامه‌ی ما به خوبی و خوشی اجرا بشه‌، البته اگه بقیه‌ی قسمت‌های کُد‌هاتون دُرست کار کنه! اما همین چند خط کد رو مثلا چاپ اعداد ۰ تا ۱۰ هستش، پس ما کُد‌های ما به این صورت باید باشه: print(0) print(1) print(2) print(3) print(4) print(5) print(6) print(7) print(8) print(9) print(10) اُووو! این همه کُد! حالا فکر کنید از ۰ تا ۱۰۰۰ باید به همین شکل کُد بنویسید! کاری با خُطوط کُدها و حتی منطقی‌ بودنش هم نداریم! اما واقعا حوصله، زمان و انرژیتون چی میشه؟ پس راه‌حل چیه؟! آفرین! حلقه‌ها، این مشکل رو به سادگی و زیبایی هر چه تمام‌ترحل کردند. پس مثال بالا رو با یک حلقه می‌نویسیم: for index in 0...5 { print(index) // Output => 0,1,2,3,4,5 } فقط با چندین خط کُد این مشکل حل شد! حالا شما می‌تونید به‌ جای عدد ۵، عدد ۱۰۰۰ یا بیشتر رو قرار بدید. پس متوجه شدید که کاربرد حلقه‌ها چقدر مهم هستن، و برای تکرار دستوراتی هستند که داده‌های زیادی رو دارند و عملا بدون حلقه‌ها باید کُد‌های زیادی بنویسید تا این داده‌ها نمایش داده بشن!. انواع داده در سوئیفت، ما با انواعی از داده سر و کار داریم که عبارت‌اند از: انواع داده‌ی صحیح و اعشاری Int۸: نوع داده‌ی عددی ۸بیت است، یعنی اینکه فقط توانایی ‌ذخیره ۱‌بایت را دارد. و مقادیر ۱۲۷ تا ۱۲۷- را پوشش می‌دهد. UInt8: این نوع داده عددی فقط و فقط یک مقدار از ۰ تا ۲۵۵ را پوشش خواهد داد و ۱‌بایت است. که در واقع از نام کوتاه‌ شده‌ی Unsigned Integer می‌آید، و به معنای نوع بدون علامت ( -‌ ) است. Int۳۲: این نوع داده ۴‌بایتی (‌ ۴ *‌ ۸ ) است، و مقداری از ۲۱۴۷۴۸۳۶۴۷ تا ۲۱۴۷۴۸۳۶۴۷- را پوشش می‌دهد. UInt32: مانند UInt8، است، با این تفاوت که فقط مقادیر صحیح بدون علامت ( - ) را قبول می‌کند و ۴‌بایت است. از مقدار ۰ تا ۴۲۹۴۹۶۷۲۹۵ را پوشش می‌دهد. Int۶۴: ‌مقداری بیشتر در خود ذخیره می‌کند! و ۸‌بایت است. یعنی اینکه مقدار عددی بیشتری تا ۲۰ رقم عدد صحیح با علامت ( + ) و بدون علامت ( - ) را ذخیره می‌کند. از مقدار ۹۲۲۳۳۷۲۰۳۳۶۸۵۴۷۷۵۸۰۸ تا ۹۲۲۳۳۷۲۰۳۳۶۸۵۴۷۷۵۸۰۸- را پوشش می‌دهد. UInt۶۴: مقادیری بیشتر ذخیره می‌کند که فقط شامل اعداد صحیح بدون علامت ( - ) است و ۸‌بایتی است. از مقدار ۰ تا ۱۸۴۴۶۷۴۴۰۷۳۷۰۹۵۵۱۶۱۵ را پوشش می‌دهد. Float: این نوع داده‌ی اعشاری است و شامل ۴‌بایت است. مقادیر اعشاری از ۱.۲E-38 تا ۳.۴E-38 را پوشش می‌دهد( تا ۶ رقم اعشار ). البته این اعدا و این نوع نوشتاری، نماد‌های علمی هستند!. Double: اعشاری با تفاوت اینکه فضای بیشتری را در اختیارمان می‌گذارد و همین‌طور دقت بالایی را هم در محاسبات به همراه دارد. ۸‌بایتی است و از مقدار ۲.۳E-308 تا ۱.۷E+308 را پوشش می‌دهد ( تا ۱۵ رقم اعشار ). خُب، برای هر کدام یک مثال می‌زنیم: var int_8_byte : Int8 = -50 print(int_8_byte) var uint_8_byte : UInt8 = 50 print(uint_8_byte) var int_32_byte : Int32 = -560 print(int_32_byte) var uint_32_byte : UInt32 = 560 print(uint_32_byte) var int_64_byte : Int64 = -1567 print(int_64_byte) var uint_64_byte : UInt64 = 1567 var float : Float = 18.5 print(float) var double : Double = 19.75 print(double) این کُد‌ها رو در اِدیتور یا IDE خودتون وارد و اجرا کنید تا نتیجه رو بصورت زنده مشاهد کنید. در این میان، دقت کنید که نوع داده‌ی خودتون رو به درستی در پروژه‌های نرم‌افزاری استفاده کنید و طبق نیاز پروژتون از داده‌ی مورد نیاز استفاده کنید. به عنوان مثال، یک قسمتی از برنامه‌ی شما نیاز به داده‌ی به اندازه‌ی ۸‌بایت داره، ولی شما میاید و یه داده‌ی ۶۴‌بایتی تعریف می‌کنید برای اون! می‌دونید چقدر از حافظَتون بدون مصرف و اِشغال‌شده باقی ‌می‌مونه؟! پس دقت کنید. نوع داده‌ی بُولیَن ( Boolean ) این نوع داده دو مقدار True یا False می‌گیره. از این نوع داده بیشتر در دستورات شرطی استفاده میشه و قسمت‌هایی از برنامه که نیاز به بررسی و دُرستی یا نادُرستی یک عبارت داره. نحوه‌ی تعریف و استفاده از اون هم به این شکل هستش: let _boolean : Bool = true // Or false print(_boolean) در این تعریف شما می‌تونید با تعریف نوع داده‌ی Bool و سپس مقدار به آن، از آن در قسمت‌های مختلف برنامه استفاده کنید. نوع داده‌های رشته‌ای و کارکتری String: یک دنباله‌ای از رشته ( همان متن ) را در خود ذخیره می‌کند. مانند: let _web_site_iostream : String = "www.iostream.ir" print(_web_site_iostream) Character: فقط و فقط یک کارکتر را قبول می‌کند( به جز کارکتر‌های کنترلی ). مانند: let _character : Character = "i" let _character_control : Character = "\n" print(_character) // Output => i print(_character_control) // Output => new line همون‌طور که مشاهده کردید، چندین نوع‌ داده‌ در زبان برنامه‌نویسی سوئیفت وجود دارد که شما باید با توجه به پروژه‌ی خودتان از آن‌ها استفاده‌ی درست کنید!. حلقه‌ها و انواع آن حلقه‌ها در سوئیفت به طور متفاوتی تعریف می‌شوند، اما همه‌ی آن‌ها کار یکسانی انجام می‌دهند! یعنی تکرار دستورات. حلقه‌ی اول، for هستش: for index in 0...5 { print(index) } در این تعریف همان‌طور که مشاهده می‌کنید، با تعریف کلمه‌ی کلید for و بعد از آن یک نام دلخواه و معنی‌دار برای اینکه مقادیر هر بار در آن ذخیره شوند (‌ در واقع نقش یک متغییر را بازی می‌کند ) و بعد کلمه‌ی کلید in و در نهایت باید یک رِنج از یک عدد تا یک عدد دیگر انتخاب کنیم که بین این‌ها با سه نقط ( ...‌ )‌ از هم جدا می‌شوند! این به این معنی است که در این تعریف عدد اولی که تعیین می‌شود، تا عدد دوم به صورت کامل اعداد در ‌index ذخیره شده و هیچ کَم و کَسری مانند یک ‌ایندِکس کم شود، ندارد. اما اگر بخواهیم یک عدد کمتر و یا در واقع یک بار کمتر حلقه تکرار شود از این تعریف استفاده می‌کنیم:‌ for index in 0..<5 { print(index) } در این صورت با آپِریِتر > می‌توانیم یک عدد و تکرار کمتر داشته باشیم. اگر بخواهیم درمورد آرایه که در جلسات دیگر صحبت می‌کنیم، یک مثال بزنیم، به این صورت هست: let _array_number = [10,20,30,40] for index in _array_number { print(index) } همان‌طور که می‌بینید، تعریف و استفاده از حلقه‌ی for به چه زیبایی و آسانی است. حلقه‌ی while، حلقه‌ی دومی هستش که به معرفی اون می‌پردازیم. این حلقه به این صورت تعریف می‌شود: var number : Int8 = 0 while (number < 10) { print(number) number += 1 } در حلقه‌ و در قسمت شرط آن شما می‌توانید هر شرطی را که باعث ورود به بدنه‌ی حلقه شود، تعریف کنید. کلمه‌ی کلید while در ابتدا تعریف می‌شود و سپس شرطی را که مد‌نظرتان است، تعریف می‌کنید ( در بین دو پَرانتِز ) و سپس در بدنه شرط، دستورات خود را می‌نویسید. در نهایت، حلقه‌ی آخر، حلقه‌ی repeat هستش که کارکرد اون دقیقا همانند حلقه‌ی do, while هستش! نحوه‌ی تعریف و استفاده از اون به این شکل است: var repeat : Int8 = 0 repeat { print(repeat) repeat += 1 } while repeat < 1 در این حلقه، بدنه‌ی حلقه که شامل دستورات هستند ابتدا اجرا می‌شود و سپس شرط بررسی می‌شود! درست همانند do, while. این حلقه با کلمه‌ی کلید repeat تعریف شده و سپس در بین آکولاد‌ها (‌ {} ) دستورات نوشته می‌شوند و بعد از آخرین آکولاد ( { ) جلوی آن و یا بعد آن کلمه‌ی کلید while و سپس شرط را می‌نویسم. البته بدون پَرانتِز!. البته این دستور فقط یک بار اجرا خواهد شد! چرا که متغییر repeat کوچکتر از ۱ نیست، بزرگتر از آن هم نیست و در واقع مساوی است ( مقدار repeat در همان وهَله‌ی اول یک بار افزایش میابد و مقدار ۱ را درون خود ذخیره می‌کند). پس شرط نادرست از آب در می‌آید و حلقه دیگر اجرا نخواهد شد. نکته:‌ دقت کنید که در تمامی حلقه‌ها نیاز به آکولاد باز و بسته برای تعریف دستورات است و شما نمی‌توانید بدون تعریف این آکولاد‌ها کُد‌های خودتان را بنویسید! پس دقت کنید. به جزء حلقه‌ی while دیگر حلقه‌ها نیازی به پَرانتِز () برای تعریف شرط، ندارند. این جلسه هم به پایان رسید و در جلسات بعد به مباحث بیشتر و کمی جزئیات بیشتر می‌پردازیم که به دانش شما اضافه‌تر شده باشه.
  22. سید محمد عباسی

    پس با این حساب، با استفاده از کلید واژه‌های ذکر شده، می‌تونیم عملا تاییده‌ی استفاده از اطلاعات شئ MessageBox یا استفاده شئ از اطلاعات کتابخانه‌ی دیگه رو صادر کنیم. امیدوارم که این بیانیه‌ی من از اطلاعات شما درست باشه، اگه نیست، بیشتر فکر می‌کنم و اگه متوجه نشدم، لطف بکنید و کمی ساده‌تر برای بنده توضیح بدید. ممنون از محبتتون.
  23. معمولا یکی از کابوس هایی که میتونه برای کسانی که از VmWare استفاده میکنند و یک توزیع لینوکس دارند که باهاش یک نرم افزار را توسعه میدهند، این هست که به هردلیلی کرنل لینوکس کرش کنه و دیگه بوت نشه در چنین شرایطی اگر اسنپ شات به روزی از سیستم عامل هاست خودتون نداشته باشید ویا یک image بک آپ درستی نداشته باشید، شاید به فکر این بیوفتید که هر طور شده بتونید جدول fat لینوکس را بازیابی کنید تا حداقل تو یک مد متنی به سورس فایلها که همانا ارزشمندترین دارائی ماهستند، دسترسی داشته باشید. خوب این سناریوی خوبی ولی تعداد ابزارهایی که بتونن این فرمت ex2fs را بخونن که بتونن فایلهای سورس شما را بازیابی کنند خیلی کم هستند و اکثر ابزارهایی هم که در اینترنت هستند 99 درصدشون سرکاری هستند. بنابراین اگر شما هم برای لینوکس هاست خودتون در برنامه وی ام ویر هارد دیسک تون را از نوع vmdk تعریف کردید و به صورت ex2fs پارتیشن کردید باید بگم خوشبختانه یک راه یکم سخت هست که بتونید در مواقع اضطراری سورس های خودتون را ریستور کنید. البته توجه داشته باشید که با روش زیر فقط میتوانید اطلاعات را بخونید چیزی نمی توانید در دیسک vmdk بنویسید.! بنابراین به یک برنامه به نام DiskInternals Linux Reader احتیاج دارید که باید نصب کنید! والبته برای سناریویی هم که در بالا اشاره شد به برنامه winhex هم نیاز دارید که در پست قبلی توضیح داده شده است. پس بعد از نصب برنامه DiskInternals کافی که فایل vmdk لینوکس خودتون را انتخاب کنید، سپس با کلیک سمت راست از منوی ظاهر شده گزینه create image را انتخاب کنید و بعد از انتخاب یک نام فایل مشخص برای دیسک ایمیج خودتون طبق تصویر بعدی عمل کنید... و بعد از اتمام ساخت فایل image disk برنامه WinHex را اجرا کنید و طبق توضیحات زیر عمل کنید... ابتدا فایل مورد نظر را باز کنید.. سپس با استفاده از گزینه ای که در تصویر پست قبلی مشخص شده فایل را بارگذاری کنید...
  24. کامبیز اسدزاده

    خواهش می‌کنم، این سری مقالات اصولاً برای افراد مبتدی تا حرفه‌ای نیاز هست، شخصاً من هم با بعضی از قسمت‌ها و اصول استانداردش مواجه نشده بودم و می‌تونم بگم با در نظر گرفتن چنین اصول و استاندارد از یک قانونی پیروی می‌کنیم که حرفه‌ای ها بهش توجه و بها می‌دهند.
  25. بله منهم موافقم تجربه نشون داده این که می فرمائید درسته و در توسعه محصول خیلی کمک میکنه! ارداتمندیم
  26. با توجه به این نظری که داری، همونطور که فکرش رو می‌کردم پس بهتره پشتیبانی به صورت چند-سکویی تحت همون API‌های استاندارد پیاده سازی بشه. کاری که همین الآنش هم انجام میدم اینطور هست که برای مثال در ویندوز با توجه به رفتار کامپایلر و همچنین رفتار مشابهش در یونیکس و لینوکس کد‌ها، کتابخانه‌ها و اساس برنامه رو توسعه میدم. متوجه شدم در کل قضیه از چه قراره! مثال و تجربه‌ی خوبی زدی دمت گرم
  27. کامبیز اسدزاده

    منظور محدود کردن نیست، در واقع شما عمل تأیید یا امضاء برای یک شیء را جهت استفاده در یک کتابخانه یا برنامه‌ی دیگر اعمال می‌کنید. این واژه‌ی کلیدی به شما اجازه می‌دهد اطلاعات کلاس ذخیره شده را در مراحل کامپایل به لینکر مشخص کنید، با توجه به مثال مربوطه استفاده از این دستور اساساً با توجه به صِفتِ dllexport به لینکر می‌گوید که شیء مورد نظر برای استفاده صادر می‌شود که توسط سایر کتابخانه‌ها (DLL) یا برنامه‌ها قابل استفاده خواهد بود. در این حالت تعاریف مربوط به اعلان‌های موجود باید در برنامه‌ی مشابه پیاده سازی شود، در غیر اینصورت خطای لینکر ساطع می‌شود. زمانی از این روش استفاده می‌شود که بخواهید DLL ای را ساخته و دیگر موارد را به آن لینک (پیوند) کنید. در صورتی که صفت dllimport مشخص شود عمل عکسِ آن صورت می‌گیرد؛ پیاده‌سازی‌های (implementation) مربوطه به آن برای استفاده در برنامه‌ی شما وارد می‌شوند. استفاده از dllimport نیز یک گزینه‌ی اختیاری است. در صورت استفاده از این کلیدواژه، کامپایلر کد کارآمد‌تری را تولید می‌کند. با این حال بهتر است شما برای دسترسی به نماد‌ها و اشیاء داده‌های عمومی از آن استفاده کنید. به مثال‌های زیر توجه کنید: __declspec(dllexport) void messageBox (std::string_view msg); __declspec(dllimport) void messageBox (std::string_view msg); معمولاً پیشنهاد می‌شود برای داشتن یک API خوب به صورت زیر پیاده سازی شود. #ifdef LIBRARY_API #define LIBRARY_API __declspec(dllexport) #else #define LIBRARY_API __declspec(dllimport) #endif نمونه مثال از فایل سرآیند: #ifndef MESSAGELIB_HPP #define MESSAGELIB_HPP #pragma once #include <iostream> #include <string_view> #include <string> #ifdef LIBRARY_API #define LIBRARY_API __declspec(dllexport) #else #define LIBRARY_API __declspec(dllimport) #endif class LIBRARY_API MessageBox { public: MessageBox(); ~MessageBox(); std::string_view message(std::string_view msg); }; #endif // MESSAGELIB_HPP تعاریف مربوطه: #include "messagelib.hpp" MessageBox::MessageBox() { } MessageBox::~MessageBox() { } std::string_view MessageBox::message(std::string_view msg) { return msg; } استفاده از کتابخانه در برنامه‌ها یا کتابخانه‌های دیگر: #include <iostream> #include "messagelib.hpp" using namespace std; int main() { MessageBox msg; cout << msg.message("Hello Boy!") << endl; std::cin.get(); return 0; }
  28. فرهاد شیری

    اصولا همیشه اعتقاد دارم که کسی که یک مطلب آموزشی را مورد پسند قرار میده باید خودش از درجه علمی بالایی برخوردار باشه که بتونه بگه مورد پسندم هست یانه! وبرای همین که من دراین سطح نیستم! که فقط بگم پسندیدم! قطعا فقط میتونم بگم تشکر بسیار آموزش مفیدی بود، جناب اسدزاده
  1. نمایش فعالیت های بیشتر
×
×
  • جدید...